2

How do I update/refresh my $scope.list when a new record is added to the db/collection - storage.set() method - please see comment in the code.

Please see code below.

angular.module("app", [])

.factory('Storage', function() {

    var storage =  {};
    storage.get = function() {
        return GetStuffHere();
    }
    storage.set = function(obj) {
        return SetStuffHere(obj);
    }
    return storage;
})
.controller("MainCtrl", function($scope, Storage) {

    $scope.addStuff = function(){

        var obj = {
            "key1" : "data1",
            "key2" : "data2"
        };
        Storage.set(obj);
       // update $scope.list here, after adding new record
    }
    $scope.list = Storage.get();

});
2
  • Can't you just add the $scope.list = Storage.get(); after the set? Commented Nov 12, 2013 at 13:33
  • @Beterraba - but this will not assign updated value to the $scope.list. Could do again $scope.list = Storage.get();, but I can image there are some better method, hence my question. Commented Nov 12, 2013 at 13:36

6 Answers 6

6

Here's an approach that stores the received data in the service as an array. It uses promises within the service to either send the previously stored array (if it exists) or makes an HTTP request and stores the response. Using promise of $http, it returns the newly stored array.

This now allows sharing of the stored array across other controllers or directives. When adding, editing, or deleting, it is now done on the stored array in the service.

app.controller('MainCtrl',function($scope, Storage){
  Storage.get(function(data){
    $scope.items=data
  });

  $scope.addItem=function(){
    Storage.set({name: 'Sue'});
  }
})

app.factory('Storage', function($q,$http) {

    var storage =  {};
    storage.get = function(callback) {
      /* see if already cached */
      if( ! storage.storedData){
        /* if not, get data from sever*/
        return $http.get('data.json').then(function(res){
          /* create the array in Storage that will be shared across app*/
          storage.storedData=res.data;
          /* return local array*/
          return storage.storedData
        }).then(callback)
      }else{
        /* is in cache so return the cached version*/
        var def= $q.defer();
        def.done(callback);
        defer.resolve(storage.storedData);
        return def.promise;
      }


    }
    storage.set = function(obj) {
     /* do ajax update and on success*/
        storage.storedData.push(obj);
    }
    return storage;
})

DEMO

Sign up to request clarification or add additional context in comments.

4 Comments

What is our .then(callback)? Is it Storage.get(function(data){ $scope.items=data }); - did not knew you can use it like that. I will update my code to use promises.
As a side note, should I wait for AJAX success on a storage.set() or push to the storedData straight away?
I would...if it fails user sees data that's different than on server and doesn't know update failed...can use other methods but need something to handle failed http
wait....if look at my comment I made inside storage set...and make request there. That way service handls all the requests, don't need them in controller
4

It's not 100% clear what you want to do, but assuming the storage is only going to update when the user updates it (i.e. there's no chance that two users in different locations are going to be changing the same stuff), then your approach should be to either:

  • Return a promise containing the newly stored object from the storage service after it's completed, and use .then(function() {...}) to set the $scope.list once it's complete.

    You would want to take this approach if the storage service somehow mutates the information in a way that needs to be reflected in the front-end (for example an id used to handle future interaction gets added to the object). Note that $http calls return a promise by default so this isn't much extra code if you're using a web service for storage.

  • Just add the object to the list on the line after you call it with $scope.list.push(obj)

If you have something that changes on the server side without input from that particular client, then I would look into using a websocket (maybe use socket.io) to keep it up to date.

1 Comment

Thank for taking a minute to comment on this. In this given example we will assume there is only single user (i.e. ignore per user save/set) - as you sad using promises and callback looks like best approach. Thanks for your input.
1

Solution below will work. However, I am not sure if it is best practice to put this in a function and call when needed (within MainCtrl):

i.e:

  • On first load
  • and then after new item added

    .controller("MainCtrl", function($scope, Storage) {
    
    $scope.addStuff = function(){
    
        var obj = {
            "key1" : "data1",
            "key2" : "data2"
        };
    
        Storage.set(obj);
    
        // rebuild $scope.list after new record added
        $scope.readList();
    
    }
    
    // function to bind data from factory to a $scope.item
    $scope.readList = function(){
        $scope.list = Storage.get();
    }
    
    // on first load
    $scope.readList();
    
    });
    

Comments

0

You have to use

$scope.list = Storage.get;

and in template you can then use i.e.

<ul>
  <li ng-repeat="item in list()">{{whateverYouWant}}</li>
</ul>

With this approach you will always have the current state of Storage.get() on the scope

1 Comment

@charlietfl please see my answer below, would be very helpful to see your solution taking in count async .get()
0

couldn't

return SetStuffHere(obj)

just return the updated list as well? and assign that:

$scope.list = Storage.set(obj);

If this is an API endpoint that returns the single inserted item you could push() it to the $scope.list object.

but maybe I'm missing something you are trying to do...

1 Comment

SetStuffHere() will return newly created object, so pushing this new item to a $scope would be much better solution then getting all data again. Thanks for your suggestion!
0

Updating your backend/Factory stuff is a basic Angular binding done by calling a set/post service. But if you want to automatically refresh your controller variable ($scope.list) based on changes occuring in your factory then you need to create a pooler like function and do something like :

.run(function(Check) {});

.factory('Storage', function() {

     var storage =  {};

     var Check = function(){
           storage = GetStuffHere();
           $timeout(Check, 2000);
     }

    // set...

    Check();
    return storage;

 })

 .controller("MainCtrl", function($scope, Storage) {

     $scope.list = Storage.storage;

5 Comments

So basically, this will check every 2s for a check? How about just doing $scope.list.push(Storage.set(obj)); in my addStuff()? Assuming Storage.set(obj); is not async & that Storage.set(obj) will return newly created record`
this looks like a really inefficient way of doing things.
I unfortunatly do not know any other way for "binding" resources, till today -> See charlietfl post. He plays with promises and it works !
May be I am missing something but my understand is that angular double bind view with controller (or scope). But does not bind scope with factories/resources.
you're right - it doesn't bind with factories or resources, but that's because there's not really a catch-all way of doing so. In a lot of cases the user themselves cause the service's data to update, so that is often a good place to update the scope (if it isn't already updated). Alternatively they offer $watch to bind to factory properties or methods if required. You just have to be careful that you're not doing too much - it's not a good idea to $watch a function that makes an http call for example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.