How to load nested JSON URLs and display in a template

52 views
Skip to first unread message

David Janes

unread,
Jun 15, 2014, 7:26:59 AM6/15/14
to ang...@googlegroups.com
I'm having a tough time solving this problem. I have data (that's dynamically loaded using $http) that looks like this

{
  "rooms": [
    {
      "floor": "Main Floor",
      "room": "Kitchen",
      "api_endpoint": [
        "/api/endpoints/urn:iotdb:device:705bf5ae4ee5f042c47c437b700b9315"
      ]
    },
    {
      "floor": "Main Floor",
      "room": "Living Room",
      "api_endpoint": []
    },
    {
      "floor": "Main Floor",
      "room": "Outside",
      "api_endpoint": [
        "/api/endpoints/urn:iotdb:device:705bf5ae4ee5f042c47c437b700b9315",
        "/api/endpoints/urn:iotdb:device:12289d6b0233d926f49b3de6bdb9e5a4"
      ]
    }
]

And I want to display something like this

<div ng-repeat="room in rooms">
    <h1>
        {{ room.room }}
        <span class="floor pull-right">{{ room.floor }}</span>
    </h1>   
    <div ng-repeat="api_endpoint in room.api_endpoints">
        <h2>
            Thing
        </h2>   
    </div>      
</div>          

The problem is each of those "api_endpoint"s represent another URL that pulls JSON that needs to be displayed when it becomes available.

I can't see any obvious or straight forward way to do this in Angular, but I'm guessing there must be. Thoughts? Solutions?

Regards,
David

Sander Elias

unread,
Jun 16, 2014, 12:02:52 AM6/16/14
to ang...@googlegroups.com

Hi David,

Well, I have no idea what those url’s return. That makes it hard to give a complete solution to your problem.

<div ng-repeat="room in rooms">
    <h1>
        {{ room.room }}
        <span class="floor pull-right">{{ room.floor }}</span>
    </h1>   
    <div ng-repeat="api_endpoint in room.api_endpoints" ng-init='data= {url:api_endpoint}'>
        <h2>
            {{resolve(data) ; data.data|json}}
        </h2>   
    </div>      
</div>

in your controller you can do this:

$scope.resolve = function(data) {
    $http.get(data.url).success(function (incoming) {
        data.data = incoming;
    });
};

It is good to note you should move the to an service, if it becomes any more complex than this.
If you have control over the back-end/server that is giving you the data, you might consider
it to generate html partials, that you can simply include using ng-include.

Regards
Sander

David Janes

unread,
Jun 16, 2014, 8:56:02 AM6/16/14
to ang...@googlegroups.com
Hi Sander,

The URLs return JSON - just displaying as raw JSON is find for this example.

I've tried this (thanks) and several variants. Unfortunately it's freaking out Angular and locking up Chrome because of an "10 $digest() iterations reached. Aborting!" error (like this: http://stackoverflow.com/questions/14376879/error-10-digest-iterations-reached-aborting-with-dynamic-sortby-predicate).

Any other thoughts? It seems to me this has to be a very common scenario. If the Angular Tutorial's main list of phones included the data from the individual phone.json URL files, this is is exactly my situation.

D.


--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/hyiN-DvsCTA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Sander Elias

unread,
Jun 16, 2014, 10:16:06 AM6/16/14
to ang...@googlegroups.com, david...@discoveranywheremobile.com

Hi David,

Yeah, I have enough thoughts, some of them are even relevant to your problem :-P

David, this is less common as you would think. You are missing the point that you can’t use raw JSON data in your view, you need to handle that first.
Mostly this kind of stuff is handled in a template directive, and data is loaded via an service. Since you are hitting the 10… limit, you are trying to do
too much in 1 go. Upping the limit is a dead end, if your app grows a bit, you need to up the ante again. Not a good idea.

Here is and idea on how to build a template directive. I put the $http in there, but you really should make a service out of it!

    app.directive('enpointHandler', ['$http',
        function ($http) {
            return {
                restrict: "E",
                scope : {uri: '='},
                template: '<div>{{endpointData.someExistingProperty}}</div>',
                link: function (scope, elm, attr) {
                    scope.$watch('uri', function (uri) {
                        if (!uri) { return; } //ignore empty uri's
                        $http.get(uri).success(function (data) {
                            scope.endpointData = data;
                        });
                    });
                }
            };
        }
        ]);
<div ng-repeat="room in rooms">
    <h1>
        {{ room.room }}
        <span class="floor pull-right">{{ room.floor }}</span>
    </h1>   
    <div ng-repeat="api_endpoint in room.api_endpoints">
       <endpoint-handler uri='api_endpoint'></endpoint-handler>
    </div>
</div>

This is just typed up in the browser out of the top of my head, so it might not work in 1 go ;)

Regards
Sander

David Janes

unread,
Jun 16, 2014, 12:39:47 PM6/16/14
to Sander Elias, ang...@googlegroups.com
OK, I've got a simple solution. Just use ng-controllers for each embedded thing and it all comes together exactly as you'd - or I'd anyway - expect.

D.

Reply all
Reply to author
Forward
0 new messages