Maintaining State When Changing Routes in AngularjS

I'm using AngularJS 1.0 and need to maintain state (user-entered data) on a page even when the user navigates (angular routing) to another page and then comes back to the original page. Here is what it looks like:

From what I've read online, the solution is to use a service/factory to store the data. Here is a snippet of my implementation (notice the comments; they address my concern):

    function cassetteController($scope, $rootScope, $http, $timeout, cassetteRepository) {
        // Need to get state from repository in case the user is coming back to this page.
        // This means every time we add some variable to our controller, we have to remember to include it here.
        $scope.userEnteredSubId = cassetteRepository.userEnteredSubId;
        $scope.cassettes = cassetteRepository.cassettes;
        $scope.numberOfCassettesToShow = cassetteRepository.numberOfCassettesToShow;
        $scope.subId1 = cassetteRepository.subId1;
        $scope.subId2 = cassetteRepository.subId2;
        $scope.subId3 = cassetteRepository.subId3;

        // Every time we alter a $scope variable, we have to remember to also alter the state in the factory.
        // This seems error-prone and tedious. Each line below is followed by a line that stores its
        // value in the factory. 
        $scope.onClickCassette = function (cassette) {
            $scope.subId1 = cassette._content[0].SolarPanel.SubId;
            cassetteRepository.subId1 = cassette._content[0].SolarPanel.SubId;
            $scope.subId2 = cassette._content[1].SolarPanel.SubId;
            cassetteRepository.subId2 = cassette._content[1].SolarPanel.SubId;
            $scope.subId3 = cassette._content[2].SolarPanel.SubId;
            cassetteRepository.subId3 = cassette._content[2].SolarPanel.SubId;

And here is the factory that stores the state:

app.factory('cassetteRepository', ['$http', '$rootScope', function ($http, $rootScope) {
    var state = {
        userEnteredSubId: '',
        cassettes: [],
        numberOfCassettesToShow: 10,
        subId1: '',
        subId2: '',
        subId3: ''

    return state;

My question is this: Really? It seems like there has to be a more elegant approach. I've only shown a portion of my controller. Every time I set a variable, I have to remember to set its counterpart in the factory where the state is maintained. Am I missing something? Is there a better approach?


If you are using this only to save values then I would use a value instead of creating a service. Here is how you set up a value in Angular:

    .value('cassetteRepository', { data: {} });

Now you can inject that value and use its data property directly so you don't have to update things twice. Here's how to use it in a controller:

    .controller('yourControllerName', ['$scope', 'cassetteRepository', function($scope, cassetteRepository) {
        // create a local scope reference if you need to use this in your view
        $scope.cassetteRepository = cassetteRepository;

        // now when you set properties on $ they are set on
        // the value and are persisted and shared across your app.
        // you can also use ng-model to two-way bind in your view.
        $scope.onClickCassette = function (cassette) {
            $ = cassette._content[0].SolarPanel.SubId;
            $ = cassette._content[1].SolarPanel.SubId;
            $ = cassette._content[2].SolarPanel.SubId;

You don't have to use the data object in your value. You could also just define the properties directly. E.g.:

.value('cassetteRepository', { userEnteredSubId = "", cassettes = [], numberOfCassettesToShow = 10, etc. })

That way you can provide default values and eliminate having the .data part.

Need Your Help

Drop selected packets at the link layer

filter ip dump packet tcpdump

I need to dump some incoming packets and then prevent them from going up the stack, so that applications won't process them.

Footer management

crystal-reports footer crystal-reports-2010

I hope I am posting to the right place.