1

I have question about how ng-repeat extracts data from arrays/obects. I initially had this setup:

Factory

   .factory('newsService', function($q) {

         var schoolnews = [
            {'ID': '1', 'image': 'image1.jpg', 'title': 'Title ...', 'itemtext': 'Full story text ...'},
            {'ID': '2', 'image': 'image2.jpg', 'title': 'Title ...', 'itemtext': 'Full story text ...'},
            {'ID': '3', 'image': 'image3.jpg', 'title': 'Title ...', 'itemtext': 'Full story text ...'}
          ];

        return {
            findAll: function() {
                var deferred = $q.defer();
                deferred.resolve(schoolnews);
                return deferred.promise;
            },

            findById: function(newsId) {
                var deferred = $q.defer();
                var newsItem = schoolnews[newsId - 1];
                deferred.resolve(newsItem);
                return deferred.promise;
            }
        }   

    });

Controllers

schoolApp.controller('newsCtrl', function($scope, newsService) {
    newsService.findAll().then(function (schoolnews) {
            $scope.schoolnews = schoolnews;
        });

})



schoolApp.controller('newsDetailCtrl', function($scope,  $stateParams, newsService) {
      newsService.findById($stateParams.ID).then(function(newsDetail) {
            $scope.newsDetail = newsDetail;
  })
})

HTML

  <ion-item class="item-text-wrap item-thumbnail-left" href="#tab/newsdetail/{{headline.ID}}" ng-repeat="headline in schoolnews">
    <img ng-src="http://http://multimedia.dev/pics/{{headline.image}}" spinner-on-load>
    <p>{{headline.title}}</p>
  </ion-item>

and

   <div ng-bind-html="newsDetail.itemtext"></div>

This all worked as expected and as I understand. I then modified my app so that it would get its data from a remote server and store a JSON string in local storage. I also modified my data structure to be an object instead of array with the ID as a key, shown below.

Factory

   .factory('newsService', function($q) {

        var newsHeadlines =localStorage.getItem('newsHeadlines') || '{"status":"READFAIL"}'; // get news as a JSON string. if newsHeadlines not found return a JSON string with fail status
        var newsHeadlinesObj = JSON.parse(newsHeadlines);// convert to an object 
        // structure of newsHeadlinesObj
        // {
        //  "56" :  {"ID" : "56", "title" : "Title ...", "image" : "image1.JPG", "itemtext" : "Full story ..."},
        //  "266" : {"ID" : "266", "title" : "Title ...", "image" : "image2.JPG", "itemtext" : "Full story ..."},
        //  "272" : {"ID" : "272", "title" : "Title ...", "image" : "image3.JPG", "itemtext" : "Full story ..."}
        // }

        return {
            findAll: function() {
                var deferred = $q.defer();
                deferred.resolve(newsHeadlinesObj);
                return deferred.promise;
            },

            findById: function(newsId) {
                var deferred = $q.defer();
                var newsItem = newsHeadlinesObj[newsId];
                deferred.resolve(newsItem);
                return deferred.promise;
            }
         }   
    });

Controllers

schoolApp.controller('newsCtrl', function($scope, newsService) {
    newsService.findAll().then(function (newsHeadlinesObj) {
            $scope.newsHeadlinesObj = newsHeadlinesObj;
        });

})


schoolApp.controller('newsDetailCtrl', function($scope,  $stateParams, newsService) {
      newsService.findById($stateParams.ID).then(function(newsDetail) {
            $scope.newsDetail = newsDetail;
  })
})

HTML

  <ion-item class="item-text-wrap item-thumbnail-left" href="#tab/newsdetail/{{headline.ID}}" ng-repeat="headline in newsHeadlinesObj"> 
    <img ng-src="http://multimedia.dev/pics/{{headline.image}}">
    <p>{{headline.title}} / {{headline.ID}}</p>
  </ion-item>

and

<div ng-bind-html="newsDetail.itemtext"></div>

My question!

My new setup works, but I don't understand how it works. Given that my new data is:

{
            "56" :  {"ID" : "56", "title" : "Title ...", "image" : "image1.JPG", "itemtext" : "Full story ..."},
            "266" : {"ID" : "266", "title" : "Title ...", "image" : "image2.JPG", "itemtext" : "Full story ..."},
            "272" : {"ID" : "272", "title" : "Title ...", "image" : "image3.JPG", "itemtext" : "Full story ..."}
     }

I was expecting

ng-repeat="headline in newsHeadlinesObj ... {{headline.title}}

NOT to work. I figured 'headline' to maybe contain an object, or the ID number and an object, I thought I would have to add more code to access an object within an object. And, by prefixing the second ID (such as "ID" : "inner272") I was able to see that headline.ID is actually the inner one.

Could someone explain how this is working? Thanks!

1 Answer 1

1

It works because your object newsHeadlinesObj has a set of properties, each property has a key and a value, for example, this property:

"56" :  {"ID" : "56", "title" : "Title ...", "image" : "image1.JPG", "itemtext" : "Full story ..."}

has the key: 56 and the value is:

{"ID" : "56", "title" : "Title ...", "image" : "image1.JPG", "itemtext" : "Full story ..."}

When you use an object with ng-repeat, angular will iterate the properties of the object, in your case the object: newsHeadlinesObj.

If in the ng-repeat you only ask for the value, like you are doing here:

ng-repeat="headline in newsHeadlinesObj ... {{headline.title}}

Angular will give you just the value, but you could ask for the key too, like this:

ng-repeat="(key, headline) in newsHeadlinesObj ... {{key}}

And then you would be able to access both: the key and the value.

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

6 Comments

Thanks! I just tried that. So 'key' is a reserved word, is it? And, if I can say, in a more simplistic way, ng-repeat simply understands the data structure, and automatically splits the key/value pairs? Is this correct? And finally, is my code correct and robust?
@KevInSol hey! no, 'key' is not a reserved word, you could do "(k, headline) in newsHeadlinesObj)" and then the key would be "k" and your headline would be "headline"... You could also do: "(myKey, item) in newsHeadlinesObj)" and then the key would be "myKey" and your headline would be "item".
@KevInSol angular checks if it's an Array and if it's not an array then it assumes that it's an object... So, yeah, it kind of "understands" your date structure. Also, your code looks totally fine to me.
Thanks, so it's (foo, bar) where foo will always be the key and bar the object. And if just (foo) then foo is the object?
@KevInSol yes and no. "so it's (foo, bar) where foo will always be the key and bar the object" <-- Yes. "And if just (foo) then foo is the object?" <-- No: if you just want the object, don't use the parenthesis.
|

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.