Angularjs Best Practice for Data Store

To share data between two controllers on the same page, you can use factories/services. Take a look at Share data between AngularJS controllers for example.

However, if this is across page reloads/refreshes, you will need to store the data in local storage and then read it upon reloading. An example of that is here: How do I store data in local storage using Angularjs?


EDIT See Jossef Harush's answer where he has written an in-depth response that covers other methods including this one.

I'd recommend using either localStorage or sessionStorage - http://www.w3schools.com/html/html5_webstorage.asp.

HTML local storage provides two objects for storing data on the client:

  • window.localStorage - stores data with no expiration date
  • window.sessionStorage - stores data for one session (data is lost when the browser tab is closed)

This assumes that you don't want to POST/PUT the data to your web service (windows service mention in your question).

If you data is an array or some sort, you can convert it to JSON to store as a string and then when you need it you can parse it back as follows - How do I store an array in localStorage?:

var names = [];
names[0] = prompt("New member name?");
localStorage["names"] = JSON.stringify(names);

//...
var storedNames = JSON.parse(localStorage["names"]);

Option 1 - custom service

You can utilize a dedicated angular service to store and share data between controllers (services are single instance objects)

service definition

 app.service('commonService', function ($http) {

        var info;

        return {
            getInfo: getInfo,
            setInfo: setInfo
        };

        // .................

        function getInfo() {
            return info;
        }

        function setInfo(value) {
            info = value;
        }
});

usage in multiple controllers

app.controller("HomeController", function ($scope, commonService) {

    $scope.setInfo = function(value){
        commonService.setInfo(value);
    };

});


app.controller("MyController", function ($scope, commonService) {

    $scope.info = commonService.getInfo();

});

Option 2 - html5 localStorage

You can use the built-in browser local storage and store your data from anywhere

writing

$window.localStorage['my-data'] = 'hello world';

reading

var data = $window.localStorage['my-data']
// ...
  • check out this awesome project: https://github.com/grevory/angular-local-storage

Option 3 - via web server api

If you need to persist data among different users, you should save it somewhere in the server side (db / cache)

function getProfile() {
    return $http.get(commonService.baseApi + '/api/profile/');
}

function updateProfile(data) {
    var json = angular.toJson(data);
    return $http.post(commonService.baseApi + '/api/profile/', json);
}

There is an option not mentioned in other answers (AFAIK).

EVENTS

  • You can use events for communication between controllers.

  • It's a straightforward communication that doesn't need a mediator (like service) and can't be wiped by the user (like HTML storage).

  • All the code is written in controllers that you are trying to communicate with and thus very transparent.

A good example how to leverage events to communicate between controllers can be seen below.

The publisher is the scope that wanna publish (in other words let others know something happened). Most don't care about what has happened and are not part of this story.

The subscriber is the one that cares that certain event has been published (in other words when it gets notified hey, this happened, it reacts).

We will use $rootScope as a mediator between publisher and a subscriber. This always works because whatever scope emits an event, $rootScope is a parent of that scope or parent of a parent of a parent.. When $rootScope broadcasts (tells everyone who inherits) about an event, everyone hears (since $rootScope is just that, the root of the scope inheritance tree) so every other scope in app is a child of it or child of a child of a child..

// publisher
angular.module('test', []).controller('CtrlPublish', ['$rootScope','$scope',
    function ($rootScope, $scope) {

      $scope.send = function() {
        $rootScope.$broadcast('eventName', 'message');
      };

}]);

// subscriber
angular.module('test').controller('ctrlSubscribe', ['$scope',
    function ($scope) {

      $scope.$on('eventName', function (event, arg) { 
        $scope.receiver = 'got your ' + arg;
      });

}]);

Above we see two controllers communicating a message to each other using an event. The event has a name, it has to be unique, otherwise, a subscriber doesn't differentiate between events. The event parameter holds autogenerated but sometimes useful data, the message is the payload. In this example, it's a string but it can be any object. So simply put all the data you wish to communicate inside an object and send it via event.

NOTE:

You can avoid using root scope for this purpose (and limit the number of controllers that get notified of an event) in case two scopes are in direct inheritance line of each other. Further explanation below:

$rootScope.$emit only lets other $rootScope listeners catch it. This is good when you don't want every $scope to get it. Mostly a high level communication. Think of it as adults talking to each other in a room so the kids can't hear them.

$rootScope.$broadcast is a method that lets pretty much everything hear it. This would be the equivalent of parents yelling that dinner is ready so everyone in the house hears it.

$scope.$emit is when you want that $scope and all its parents and $rootScope to hear the event. This is a child whining to their parents at home (but not at a grocery store where other kids can hear). This is a shortcut to use when you wanna communicate from the publisher that is a child or n-th child of the subscriber.

$scope.$broadcast is for the $scope itself and its children. This is a child whispering to its stuffed animals so their parents can't hear.

EDIT: I thought plunker with a more elaborate example would be enough so I decided to keep is simple here. This elaborate explanation should be better.