1

I'm trying to display a JSON file in the HTML using the AngularJS service with array and hash/dictionary variables. The array binding is working fine, but the hash variable value is not being reflected the HTML. In the console, I could see the hash value also being set, but for some reason it's not getting displayed in the HTML. If I use the angular.service, it doesn't work... But if I just call the $http.get directly inside the controller, it works fine. Is this a bug, or am I missing something here?

I tried out a simple sample program in the jsfiddle, and having the same problem... Sample JSON display

var app = angular.module("sampleJSONApp", []);

app.service("sharedProperties", function ($http) {
    var json_data_arr = [];
    var json_data_hash = {};
    return {
        getJSONDataHash: function () {
            if (0 == json_data_arr.length) {
                var sample_json = "https://dl.dropboxusercontent.com/s/i9pu80k962g6d3u/sample.json";
                $http.get(sample_json).success(

                function (result) {
                    json_data_hash = result;
                    var i = 0;
                    for (k1 in json_data_hash) {
                        for (k2 in json_data_hash[k1]) {
                            json_data_arr[i] = k1 + ":" + k2 + ":" + json_data_hash[k1][k2];
                            i++;
                        }
                    }
                });
            }
            return json_data_hash;
        },
        getJSONDataArr: function () {
            return json_data_arr;
        }
    }
});

app.controller("displayJSON", function ($scope, sharedProperties) {
    $scope.json_data_arr = sharedProperties.getJSONDataArr();
    $scope.json_data_hash = sharedProperties.getJSONDataHash();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body data-ng-app="sampleJSONApp">
<h1 style=bold>Sample JSON display</h1>

<br/>
<div data-ng-controller='displayJSON'> 
    <span data-ng-model='json_data_arr'>
        JSON Data Array: {{json_data_arr}}
        <br/>
        <ul data-ng-repeat='ele in json_data_arr'>
        <li>{{ele}}</li>
        </ul>
    </span>

    <br/> 
    <span data-ng-model='json_data_hash'>
        JSON Data Hash: {{json_data_hash}}
    </span>
    <br/> 
    <span data-ng-repeat='(k1,k2_v2) in json_data_hash'>
        <ul data-ng-repeat='(k2,v2) in k2_v2'>
            <li>{{k1}}</li>
            <li>{{k2}}</li>
            <li>{{v2}}</li>
        </ul>
    </span>

</div>
</body>
abhijithda
  • 208
  • 3
  • 10
  • Is there any difference in the way angularjs.service treats array and hash? While the array variable is working, the hash variable isn't. Here are the jsfiddle samples:- [Array](http://jsfiddle.net/abhijithda/cjm1f8mq/) and [Hash](http://jsfiddle.net/abhijithda/bde4daom/). – abhijithda Dec 27 '14 at 10:48

1 Answers1

1

The problem is because response in not available yet when you are trying to use it. AJAX takes it time to load. Instead of returning value in synchronous manner return a Promise object, which stores its state and allows you to use its then-able methods, providing callback function to be called once data is available.

Here is a modified version of your code which makes proper use of promises objects returned by $http service:

getJSONDataHash: function () {
    if (0 == json_data_arr.length) {
        var sample_json = "https://dl.dropboxusercontent.com/s/i9pu80k962g6d3u/sample.json";
        return $http.get(sample_json).success(
            function (result) {
                json_data_hash = result;
                var i = 0;
                for (var k1 in json_data_hash) {
                    for (var k2 in json_data_hash[k1]) {
                        json_data_arr[i] = k1 + ":" + k2 + ":" + json_data_hash[k1][k2];
                        i++;
                    }
                }
                return json_data_hash;
            }
        );
    }
    else {
        return $q.when(json_data_hash);
    } 
},

and then you would use it in controller this way:

sharedProperties.getJSONDataHash().then(function(data) {
    $scope.json_data_hash = data;
});

Demo: http://jsfiddle.net/aykcnrt6/19/

Also take a look at this question for general information on the problem How do I return the response from an asynchronous call?.

Community
  • 1
  • 1
dfsq
  • 191,768
  • 25
  • 236
  • 258
  • Thanks for the info on promises. By the way, I'm curious as to why array would work when hash wouldn't. Is there any difference in the way angularjs.service treats array and hash? Here are the jsfiddle samples which are almost same except the variable types (and their assignments):- [Array](http://jsfiddle.net/abhijithda/cjm1f8mq/) and [Hash](http://jsfiddle.net/abhijithda/bde4daom/). – abhijithda Dec 27 '14 at 10:44
  • No, it's not about the difference between array and object. They are the same problem here in this case. The reason why array works for you is that for array you call `sharedProperties.getJSONDataArr` which returns a **reference** to `json_data_arr` object (array). Later this array is populated with data, and due to Angular digest cycles gets rendered during the next digest loop. However for `json_data_hash` you call `sharedProperties.getJSONDataHash();` which immediately returns empty object. – dfsq Dec 27 '14 at 10:47
  • .... Later when AJAX has completed you do `json_data_hash = result;` but the tricky thing is that this assignes the **new** object reference. So the previous `json_data_hash` is never updated with data. – dfsq Dec 27 '14 at 10:48
  • That's it. I was overwriting the reference of the `json_data_hash` variable. It works fine now... And thanks for the example usage of promise. – abhijithda Dec 27 '14 at 23:27
  • Here is the updated jsfiddle that's working now: [Sample JSON display using Array & Hash](http://jsfiddle.net/aykcnrt6/23/) – abhijithda Dec 27 '14 at 23:44