4

I'm new to Angular. I have a single page application with a navbar which maps to some html "sections". Each section is visualized monitoring the state of a variable by the Angular directives ng-show.

After the first load all my sections are loaded and all HTML is in the browser. Now I can do some operations and save an object in sessionStorage. But the Angular expression referred to it does not load new data! I would like a classical data binding between my expression and my session storage. How can I do this?

Here there is a snippet of my html:

    <div class="container" ng-show="panels.isSelected(2)" ng-controller="DataController as pdc">
        {{pdc.myData.property_foo}}         
    </div>

and this is the controller to load data from sessionStorage

.controller('DataController', ['$window',  function($window) {

  pdc = this;

  //myData is an object
  pdc.myData = JSON.parse($window.sessionStorage.getItem("myData"));

}]);

Angular evaluates the value of myData only at the first loading of the page, instead of triggering a new evaluation of the expression each times myData changes...that's my problem...

Edit: I simulate my problem in this plnkr http://plnkr.co/edit/vG1IGOPsJlbUPOzYsY03?p=preview As you can see, when you press update the value displayed from session storage is not updated. You can see new values only by refreshing the page.

floatingpurr
  • 7,749
  • 9
  • 46
  • 106
  • not clear what you mean by `myData changes`. How is it being changed ? The changes should be connected by a service probably so that you are changing the live object before storing in sessionstorage – charlietfl Jul 14 '15 at 17:21
  • i.e. when I press a button a function is triggered passing `myDataObject`. This function does something like: `$window.sessionStorage.setItem("myData", JSON.stringify(myDataObject));` – floatingpurr Jul 16 '15 at 09:19
  • @superciccio14 check out forked plunker ;) – rzysia Jul 16 '15 at 11:11
  • @rzysia can you post the link of forked plunker? I had a problem with plnkr... thanks : ) – floatingpurr Jul 16 '15 at 11:27
  • 1
    @superciccio14 aww, it overhelmed me, I don't know how to update it for all :P I just added one line, as it's in my answer - `pdc.myData = value;` into update function and myData was updated after click "Update" button ;) – rzysia Jul 16 '15 at 11:31
  • 1
    @superciccio14 ok, I've created a new one ;) http://plnkr.co/edit/wwoiChlrliQ59lRBT7j0?p=preview – rzysia Jul 16 '15 at 11:42

3 Answers3

2

Expressions, which are simply in controller, are called once - when controller is loaded. So your updating wont changing myData value. What you should do is to add updating myData in your update function:

pdc.update = function ( value ) {
    $window.sessionStorage.setItem("myData", value);
    pdc.myData = value;
};
rzysia
  • 737
  • 1
  • 11
  • 26
  • wow, it works! My real code is a bit more complicated of that plnkr but now I have understood the logic. As you can see in my first post, I have a @rzysia controller for reading local storage value in that piece of html. That snippet of html is displayed only after pressing an update button. I update the value `pdc.myData = JSON.parse($window.sessionStorage.getItem("myData"))` but why does not work? – floatingpurr Jul 16 '15 at 12:16
  • because value written in input isn't JSON object - it's simple plain text, no need to parse it – rzysia Jul 16 '15 at 12:20
  • @superciccio14 try update with this: `pdc.myData = $window.sessionStorage.getItem("myData");` – rzysia Jul 16 '15 at 12:23
  • In my real code myData is an object...my problem still lies in the update of value referred to session Storage in different snippets of html loaded only once. Here is a plnkr where you can see the problem: http://plnkr.co/edit/gFqHPw2frdL38PkWo81x?p=preview – floatingpurr Jul 16 '15 at 13:21
2

You can pass a function to $scope.$watch to evaluate data that is not present on $scope. For instance, sessionStorage, this, SomeService or any data source really.

So, to do what you are asking you should inject $scope into your controller, set up a $watch for the return value of a function, and update this.myData to said value.

app.controller('DataController', ['$window',  '$scope', function($window, $scope) {

  pdc = this;

  $scope.$watch(function () {
    return $window.sessionStorage.getItem('myData');
  }, function (value) {
    pdc.myData = value;
  });

  pdc.update = function ( value ) {

    $window.sessionStorage.setItem("myData", value);

  };

}]);

Alternatively, you could reverse this (makes a little bit more sense in my opinion):

$scope.$watch(function () {
  return pdc.myData;
}, function (value) {
  $window.sessionStorage.setItem('myData', value);
});

pdc.update = function (value) {
  pdc.myData = value;
};

updated plunker

  • Wow it works! I prefer not using $scope since I'm using [Controller As](http://toddmotto.com/digging-into-angulars-controller-as-syntax/) syntax – floatingpurr Jul 16 '15 at 12:07
  • 1
    That's all good and well, but you will need some sort of medium to connect the sessionStorage with `pdc`. To rid yourself of the $scope injection, you could utilize [Object getters](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) to achieve something similar. –  Jul 16 '15 at 12:10
  • Oh and please dont forget to accept the given answer if you're satisfied with it. –  Jul 16 '15 at 12:11
  • Thanks a lot, your answer is super-helpful but I'm still looking for a way to fix my problem without passing via `$scope` – floatingpurr Jul 16 '15 at 13:15
  • In other words: isn't there a way to have a 2-ways data binding with _view_ and _session storage_ like happens for _views <> models_ – floatingpurr Jul 16 '15 at 13:35
  • 1
    No, `sessionStorage` lives outside the world of angular. You have to manually let angular know that the sessionStorage has been updated and trigger the appropriate event (in this case, a `$digest` through the `$watch`). –  Jul 16 '15 at 14:25
  • Ok thanks a lot. I have another question but is off from this topic. Accepted : ) – floatingpurr Jul 16 '15 at 14:56
0

Auth0 has a plugin to work with local and session storage and its called Angular-Storage.

It works like this:

  1. First you implement this plugin in the definition of your app:

angular.module('angularStorageApp', ['angular-storage']);

  1. To set an object in your storage you use this:

angular.module('angularStorageApp').controller('testCtrl', function(store) { store.set('obj', myObj); }

  1. To get an object from your storage you use this:

angular.module('angularStorageApp').controller('testCtrl', function(store) { var myObjSaved = store.get('obj'); }

Downloads:

Angular-Storage for production:

Angular Storage .min

Angular-Storage for development:

Angular Storage

Jean Cedron
  • 702
  • 3
  • 14
  • My problem is not saving and loading data in local storage. I need a way to trigger the evaluation of the expression each times `myData` changes in local storage... – floatingpurr Jul 16 '15 at 09:36
  • I have just tried to use the library in this plnkr http://plnkr.co/edit/jll5PnUbPD06RD9xOpgZ?p=preview but it did not fix my problem :( – floatingpurr Jul 16 '15 at 11:21