19

I have an app with a ng-view that sends emails to contact selected from a contact list. When the users select "Recipient" it shows another view/page where he can search, filter, etc. "Send email" and "Contact list" are different html partials that are loaded in the ng-view.

I need to keep the send form state so when the users select someone from the Contact List it returns to the same point (and same state). I read about different solutions ($rootScope, hidden divs using ng-show, ...) but I want to know if UI-router will help me with it's State Manager. If not, are there other ready-to-use solutions?

Thanks!

Jorgito Gutierrez
  • 479
  • 2
  • 5
  • 12
  • possible duplicate of [AngularJS - saving data between routes](http://stackoverflow.com/questions/16802857/angularjs-saving-data-between-routes) – Dan Dascalescu Oct 24 '14 at 11:55

3 Answers3

23

The solution i have gone with is using services as my data/model storage. they persist across controller changes.

example

the user service ( our model that persists across controller changes )

app.factory('userModel', [function () {
    return {
        model: {
            name: '',
            email: ''
        }
    };
}]);

using it in a controller

function userCtrl($scope, userModel) {
    $scope.user = userModel;
}

the other advantage of this is that you can reuse your model in other controllers just as easly.

Anton
  • 7,709
  • 5
  • 31
  • 33
  • I neved used services. It looks fine. But what if model is created based on a route parameter (eg: $routeParams.myId)? – Jorgito Gutierrez Aug 07 '13 at 10:30
  • 2
    you would store the results in the service rather than the controller. everything else can be the same – Anton Aug 07 '13 at 11:19
  • 2
    It appears that your example is incomplete, you need a way to [broadcast](http://onehungrymind.com/angularjs-communicating-between-controllers/) changes in your service model to other controllers. [This example](http://stackoverflow.com/a/16559855/168815) also accounts for saving state when navigating away from the app altogether. – Jonathon Hill Feb 26 '14 at 20:13
  • @JonathonHill the example is specific to the question ( i hope ). the link to the example you have commented on happens to be mine as well :), and yes it give more context to on how to implement the specifics – Anton Feb 27 '14 at 21:49
  • @Anton The very disadvantage I see in your approach because I am just experiencing it... is the fact that you can not inject the $scope into a factory thus you can not have computed properties in your userModel which would change when the user types into a textbox, but your whole userModel is bound to the $scope.user thats a problem a real one. – HelloWorld Oct 12 '14 at 20:50
  • 1
    If you're only storing some data like name and email, the [Angular FAQ](https://docs.angularjs.org/misc/faq) recommends not using a service "just to store and return some bits of data". You can use a a [value](https://docs.angularjs.org/guide/providers) instead. – Dan Dascalescu Oct 27 '14 at 01:22
9

I'm not sure if this is recommended or not, but I created a StateService to save/load properties from my controllers' scopes. It looks like this:

(function(){
    'use strict';

    angular.module('app').service('StateService', function(){

        var _states = {};

        var _save = function(name, scope, fields){
            if(!_states[name])
                _states[name] = {};
            for(var i=0; i<fields.length; i++){
                _states[name][fields[i]] = scope[fields[i]];
            }
        }
        var _load = function(name, scope, fields){
            if(!_states[name])
                return scope;
            for(var i=0; i<fields.length; i++){
                if(typeof _states[name][fields[i]] !== 'undefined')
                    scope[fields[i]] = _states[name][fields[i]];
            }
            return scope;
        }

        // ===== Return exposed functions ===== //
        return({
            save: _save,
            load: _load
        });

    });
})();

To use it, I put some code at the end of my controller like this:

angular.module('app').controller('ExampleCtrl', ['$scope', 'StateService', function ($scope, StateService) {
    $scope.keyword = '';
    $scope.people = [];

    ...

    var saveStateFields = ['keyword','people'];
    $scope = StateService.load('ExampleCtrl', $scope, saveStateFields);
    $scope.$on('$destroy', function() {
        StateService.save('ExampleCtrl', $scope, saveStateFields);
    });
}]);
JstnPwll
  • 8,585
  • 2
  • 33
  • 56
2

I have found Angular-Multi-View to be a godsend for this scenario. It lets you preserve state in one view while other views are handling the route. It also lets multiple views handle the same route.

You can do this with UI-Router but you'll need to nest the views which IMHO can get ugly.

Keith
  • 20,636
  • 11
  • 84
  • 125