0

It seems like Angular re-renders an entire view when a route changes. See this example: http://jsfiddle.net/RSHG8/1/

html:

<div class="nav">
    <a href="#/one">One</a><a href="#/two">Two</a>
</div>
<div ng-app="app" id="ng-app">
    <div ng-view=ng-view></div>
</div>

var app = angular.module('app', []);

js:

app.config(function ($routeProvider) {
    $routeProvider.when('/one', {
        template: 'Template {{template}}<br>Enter some text: <input type="text" /> then click "Two"',
        controller: 'one'
    })
        .when('/two', {
        template: 'Template {{template}}<br>Click back to view "One" to see changes undone',
        controller: 'two'
    })
        .otherwise({
        redirectTo: '/one'
    });
});

app.controller("one", function ($scope) {
    $scope.template = "One";
});

app.controller("two", function ($scope) {
    $scope.template = "Two";
});

Text entered by the user is forgotten when the switching between views. This will be a problem with non-angular stuff too. E.g. a jQuery expand-collapse plugin. If a user expands a certain number of elements, leaves the view and comes back, the state will be reset to everything collapsed.

Is it possible to get Angular to simple show / hide views, rather than wipe an re-render when routes change?

Fergal
  • 2,484
  • 2
  • 36
  • 48
  • sure. but not with ng-view. you may use ng-show and show only the part of your page that should be visible – michael Jan 22 '14 at 15:26
  • Would I need a top level controller that controls what view to show / hide, then controllers for each of the views? – Fergal Jan 22 '14 at 15:39
  • yes, this would be a way... – michael Jan 22 '14 at 15:40
  • I use `ui-router` to solve this problem – Ilan Frumer Jan 22 '14 at 15:50
  • I created a little demo for you to check: http://plnkr.co/edit/i2OTfWQrhkCi0pztH4ns?p=preview – Ilan Frumer Jan 22 '14 at 17:00
  • @IlanFrumer - place an input onto one of the views and you'll see the contents gets wiped out if view is changed. Here is what I have using ng-show. Would this be "valid angular"? http://jsfiddle.net/RSHG8/8/ – Fergal Jan 22 '14 at 17:45
  • @Fergal The trick is to keep the model on the parent state. You can also implement a persistent layer with a service. I do that with localStorage, my model is persisted even if the user reload the browser. Check again: http://plnkr.co/edit/i2OTfWQrhkCi0pztH4ns?p=preview – Ilan Frumer Jan 22 '14 at 17:52
  • That only works because the input box is bound to the model. My question states that I want the state of the dom to be maintained, event if non-angular stuff is happening. i.e. if you have an input box that angular doesn't track, and the user fills it in, the contents will be removed when the view re-renders. – Fergal Jan 22 '14 at 18:07
  • First, What's bad with persisting data to a view model , If you want to save it to a localstorage you must do it anyway. More, the `ngShow` hack is only acceptable with very few views. If you have a big application you cannot afford keeping that much of DOM elements and also `$watchers` is a big issue. I can create a `ngRoute` enhanced version with option to preserve the view but I don't see a real use case. – Ilan Frumer Jan 22 '14 at 18:28
  • BTW, I'm working on an angular service which (lazily) creates shadow DOM elements and provides API for directives to reuse them and bind them to plugins. I need it because tons of plugins leak to memory and not providing any api for unloading them. This could also help to preserve state of some components like you need. – Ilan Frumer Jan 22 '14 at 18:36

1 Answers1

0

You can try assigning a ng-model to the input tag and store the value in a parent controller.

HTML

<div class="nav">
    <a href="#/one">One</a><a href="#/two">Two</a>
</div>
<div ng-app="app" id="ng-app">
    <div controller="AppCtrl">
        <div ng-view=ng-view></div>
    </div>
</div>

var app = angular.module('app', []);

JS

app.config(function ($routeProvider) {
        $routeProvider.when('/one', {
            template: 'Template {{template}}<br>Enter some text: <input type="text" ng-model="$parent.inputValue" /> then click "Two"',
            controller: 'one'
        })
            .when('/two', {
            template: 'Template {{template}}<br>Click back to view "One" to see changes undone',
            controller: 'two'
        })
            .otherwise({
            redirectTo: '/one'
        });
    });

    app.controller("AppCtrl", function AppCtrl($scope) {
        $scope.inputValue = "";
    });

    app.controller("one", function ($scope) {
        $scope.template = "One";
    });

    app.controller("two", function ($scope) {
        $scope.template = "Two";
    });
XPX-Gloom
  • 601
  • 5
  • 11
  • Only works because you are using angular to bind the input box. What about a plugin that does stuff to the dom? You'd have to track all of those actions in a model too. – Fergal Jan 22 '14 at 18:15
  • You are right, it doesn't work for manipulating DOM. I don't think angular route will work in this case. If you don't mind using plugin, ui-router will solve your problem. – XPX-Gloom Jan 22 '14 at 18:42