0

UPDATE: I added {{else}} to the nested each and it really seems the template does not iterate over individual spots. It was foolish to think that the log helper would not fire up in such situations. Ill try to dig deeper.

UPDATE2 Thanks for the first answer. Probably not counting from 0 on array indexes makes forEach function to behave funny. 1-st level of each works just fine, 2nd not at all. I will try to change my script so I store X Y coordinates differently. Even though this was convienient.

So I generated a simple array in my IndexController

grid: function(){
  //Lets generate a 2-dimensional grid
  var data = [];
  var limits = this.get('limits');
  // console.log(limits);
  for(var y = limits.min.y; y <= limits.max.y; y++){
   data[y] = new Array(this.get('numberOfColumns'));
   for(var x = limits.min.x; x <= limits.max.x; x++){
    data[y][x] = 0;
   }
  }
  console.log(data);
  // this.get('spots').forEach(function(spot){
   // console.log('Y '+spot._data.y+' X '+spot._data.x);
   // data[spot._data.y][spot._data.x] = spot._data;
   // console.log(spot);
  // });

  return data;

 }.property('limits','numberOfColumns')

Problem is, when I try to iterate over this array in my template I get a lot of undefined values and the html content does not render at all.

{{#each gridrow in grid}}
  <div class="gridRow {{unbound is-even _view.contentIndex}}">
  {{#each spot in gridrow}}
   {{!-- {{log spot}} --}}
   {{!-- {{spot-unit class='inline-block'}} --}}
   {{log "test"}}
   <div class="spot"></div>
  {{/each}}
  </div>
 {{/each}}

"Test" gets logged 800 times, although it should get logged about 50 times. No div.spot gets rendered. I guess its because of some ember meta data which get appended to the array.

I went through quite a lot of API and guides and couldnt find where should I generate such arrays. Should it be in the form of Fixtures? That doesnt seem right. Should it be simple model (therefore no ember data)? Then I would deal with multiple models situation which I would like to avoid if possible. If I generated this array on the server side with data already merged to it, things would be much simpler in the end, but before I go this way, I would really like to know where to properly generate such things on client side.


More info on what I am trying to achieve: I need to generate simple grid on client side consisting of empty tiles which I afterwards fill out with server data. Some of them will remain empty, thats why I cant count on server data alone, some tiles would be missing and grid would be broken.

Martin Malinda
  • 1,573
  • 11
  • 20

1 Answers1

1

You're setting array items starting from limits.min.y and limits.min.x indices, which, as I guess, can be greater than 0. So, let's look at your piece of code in this case:

var data = [];
var limits = this.get('limits');
for(var y = limits.min.y; y <= limits.max.y; y++){
    data[y] = new Array(this.get('numberOfColumns'));
    for(var x = limits.min.x; x <= limits.max.x; x++){
        data[y][x] = 0;
    }
}

Here, if limits.min.y > 0, data[i] for any i < limits.min.y will equal to undefined. Same thing for limits.min.x. So, better way is to rewrite as follows:

var data = [];
var limits = this.get('limits');
for(var y = 0; y <= limits.max.y - limits.min.y; y++){
    data[y] = new Array(this.get('numberOfColumns'));
    for(var x = 0; x <= limits.max.x - limits.min.y; x++){
        data[y][x] = 0;
    }
}
undeletable
  • 1,375
  • 12
  • 11
  • Thanks for the input, I am aware of this danger, but I need the array indexes start counting from the limit values, not from 0. This worked well for me in plain javascript, now I am injecting this logic to Ember and its behaving funny. I can inspect the whole array of arrays in console and it looks fine yet only the first level of #each functions works well. – Martin Malinda Nov 16 '14 at 18:41
  • Cant use For function properly in handlebars so Ill have to count from 0. Ill try to store the X Y coordinates in some object I guess. Thanks again. – Martin Malinda Nov 16 '14 at 19:01
  • The optimal solution depends on the design of your app. You can store min/max values somewhere. You can add extra check into template: `{{#each gridrow in grid}}{{#if gridrow}}{{#each spot in gridrow}}{{#if spot}}some_stuff{{/if}}{{/each}}{{/if}}{{/each}}`. But these if helpers won't work if the corresponding item equals 0. So, you can turn your array items into objects: `{value: 0}`. – undeletable Nov 16 '14 at 19:28
  • 1
    Regarding second level of data. In Ember, observers, computed properties and helpers for arrays fork correctly if you push items to them with pushObject method. So, according to written above, this should be like that: `for(var x = limits.min.y; x <= limits.max.x ; x++){ data[y].pushObject({value: 0}); }` – undeletable Nov 16 '14 at 19:29
  • 1
    Or, better way is to check index directly in template. Please take a look at http://stackoverflow.com/questions/8870785/positional-index-in-ember-js-collections-iteration or stackoverflow.com/a/14113688/3887471 – undeletable Nov 16 '14 at 19:29
  • I actually use _view.contentIndex in my code sample. Ill try to read more on Ember.Array. I briefly checked Ember.Set and Ember.CollectionView. It both looks promising. – Martin Malinda Nov 16 '14 at 19:46
  • CollectionView doesn't look like the thing you need here, it should be used for generation of array of similar-type views. – undeletable Nov 16 '14 at 19:50