Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested HandlebarsJS #each helpers with EmberJS not working

I'm slowly starting to get the hang of EmberJS. Unfortunately I've run into an issue I can't seem to work out.

I have a complex data-structure, which I retrieve through JSON, with multiple nested arrays and I can't seem to nest #each helpers.

I've setup my template as follows (shortened):

{{#each Servers}}
     <div class="server">
          <h1>{{unbound Name}}</h1>
          Time: {{jsonDate CurrentTime}}<br />

          <table>
               {{#each Processes}}
                    <tr>
                         <td>{{unbound Name}}</td>
                         <td>{{unbound Location}}</td>
                    </tr>     
               {{/each}}
          </table>
     </div>
{{#/each}}

The second loop doesn't seem to run, when I modify Ember to log a message, #the second each is called, but it seems it doesn't know what to do.

When I replace the second #each with #Queue, it works, but right before the -element an "undefined"-text is inserted for every element in the list (minus 1).

When I move the #each outside of the other loop and put in the direct path to Queue (eg. Servers.0.Queue) it works fine, so it's certainly not the data.

How do I fix this? If nested #each is not possible, how do I prefend the "undefined"-text for the other method? Any other possibilities?

PS. I use unbound for performance reasons, I update the Servers object in one go and observe that, so there is no need to use bound properties - as I've noticed it significantly reduces browser performance (13% CPU Usage, whereas unbound gave me 0%). Not sure if related.

EDIT

Please see: http://jsfiddle.net/PTC9B/7/

The ServerOverview2a-method works after all, apparently ServerOverview2b generates the "undefined"-text I described earlier - probably should file a bug report for that?

My question now is: Why do nested #each not work whereas #Processes does?

like image 500
Lennard Fonteijn Avatar asked Feb 20 '23 17:02

Lennard Fonteijn


2 Answers

It looks like the properties in your hash are causing the troubles: using an Uppercase property Processes doesn't work - if you change it to processes the each helper works as expected, see http://jsfiddle.net/pangratz666/ndkWt/:

<script type="text/x-handlebars" data-template-name="app-server">
    <h1>Default</h1>
    {{#each data.Servers}}
        <div class="server">
            <h1>{{unbound this.Name}}</h1>

            Time: {{unbound this.CurrentTime}}<br />

            <table>
                {{#each this.processes}}
                    <tr>
                        <td>{{unbound Name}}</td>
                        <td>{{unbound Location}}</td>
                    </tr>     
                {{/each}}
            </table>
        </div>
    {{/each}}
</script>​
App = Ember.Application.create({
    ready: function() {
        Ember.View.create({
            templateName: 'app-server',
            dataBinding: 'App.dataController.data'
        }).append();

        App.dataController.getServers();
    }
});

App.dataController = Ember.Object.create({
    data: {},
    getServers: function() {
        this.set('data', Ember.Object.create({
            "Servers": [
                {
                "Name": "USWest",
                "CurrentTime": "1337",
                "processes": [
                    {
                        "Name": "apache.exe",
                        ...
                    }
                ]}
            ]
        }));
    }
});​

IMHO referring to this.Processes should work in the #each helper, so this might be a bug. Are you able to change the property names of the JSON which you get from the server? Otherwise you might write a helper which lowercases your property names of a JSON before it's used ...


Another note: the Application#ready didn't work in your provided JSFiddle, because you specified the JS to be executed onDomReady (select dropdown in upper left corner of JSFiddle). If you change this to no wrap you can access App within your ready callback.


Another note about naming: instances should be named lowerCase and classes UpperCase. So it would be App.serverOverview1 = Ember.View.create({ ... }); in your example.

like image 100
pangratz Avatar answered Mar 26 '23 20:03

pangratz


Ember attempts to infer whether your path is absolute (global) or relative (local) by whether or not it has uppercase properties. In this case, Ember is looking for the global Processes property which doesn't exist. The simple solution is to use lowercase as @pangratz has pointed out. See http://www.emberist.com/2012/04/09/naming-conventions.html for more information.

like image 20
Peter Wagenet Avatar answered Mar 26 '23 19:03

Peter Wagenet