ng-repeat and object / array structure

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!

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.