Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ember.js displaying list of items, each item with it's own view/controller

What I want to achieve: create controller with view, and in this view I have list of 'Gallery' objects. Each item has it's own view and controller.

All files are here: https://gist.github.com/7e72bb2f532c171b1bf3

It works as intended, after hovering some text is shown/hidden, but personally I think that this it's not so good solution.

I think that I maybe should use {{collection}} helper, but there is no documentation for it on ember.js page (there is some in code, but I'm not sure if this helper is not a little bit outdated, as in source it says "// TODO: Don't require all of this module").

I tried to use itemController property, but then I still have template in one file.

Also tried to use {{render}} helper in {{#each}}, but then it throw error.

So, It is there a better/cleaner way to achieve what I want?

EDIT

After making everything as in explanation provided by Michael Grassotti, I have strange behaviour - property to template is taken fron itemController, but {{action}} helper binds to parent controller. I have made screenshot to show what I'm dealing with.

enter image description here

Basically "this" in itemView points to right controller (itemController) but target property has parent controller.

After making {{action "deleteGallery" this target="this"}} and clicking it, I have error as in screenshot. At this moment, I'm running out of ideas...

EDIT2:

ok, I'm overthinking it, itemController is only for defining computed properties, not for writing {{action}} handlers.

EDIT3: I think that my problem with itemController and event target will be fixed. https://github.com/emberjs/ember.js/issues/1846

like image 249
Kamil Biela Avatar asked Dec 16 '22 14:12

Kamil Biela


2 Answers

I think that I maybe should use {{collection}} helper, but there is no documentation for it on ember.js page (there is some in code, but I'm not sure if this helper is not a little bit outdated, as in source it says "// TODO: Don't require all of this module").

Agreed. Collection helper still works but I'm not certain it will be part of the public-api going forward. Best to stick with the {{#each}} helper if you can.

I tried to use itemController property, but then I still have template in one file.

The itemController property is a good start. that's the best way to give each item it's own controller.

Also tried to use {{render}} helper in {{#each}}, but then it throw error.

Yeah the {{render}} helper is not designed for use within an {{each}} block.

So, It is there a better/cleaner way to achieve what I want?

Yep. For starters use the itemController property. Then to give each it's own view, provide an itemViewClass option to the {{each helper}}. For example:

# in galleries_index.hbs
{{each controller itemViewClass="App.GalleriesIndexItemView"}

See the "blockless use" section of api docs for the each helper for detail.

Then customize App.GalleriesIndexItemView to specify a template:

App.GalleriesIndexItemView = Ember.View.extend({
    templateName: "galleries_index_item",
    tagName: 'li',
    classNames: ['span4'],
    hover: false,
    mouseEnter: function() {
        this.set('hover', true);
    },
    mouseLeave: function() {
        this.set('hover', false);
    }
});

and move html from the each helper to into the template:

# galleries_index_item.hbs
  <div class="thumbnail">
      <a href="#">
          <img src="images/300x200.gif" alt="">
      </a>
      <div class="caption">
          <h4>{{name}}</h4>              
          {{#if view.hover}}
              <button {{action editGallery this }} class="btn btn-mini" type="button">Edit</button>
              <button {{action deleteGallery this}} class="btn btn-mini" type="button">Delete</button>
          {{/if}}
      </div>
  </div>

Now every item has it's own view and controller.

like image 191
Mike Grassotti Avatar answered Dec 18 '22 03:12

Mike Grassotti


I suggest you to use an Ember.CollectionView.

Your galleriesIndex template will looks like:

<div class="container">
    <div class="row">
        <div class="span12">
            {{view App.GalleriesListView contentBinding="this"}}
        </div>
    </div>
</div>

The view:

App.GalleriesListView = Ember.CollectionView.extend({
    classNameBindings: [':thumbnail', ':thumbnails-list'],
    itemViewClass: Ember.View.extend({
        templateName: "galleriesListItem",
        hover: false,
        mouseEnter: function() { this.set('hover', true); },
        mouseLeave: function() { this.set('hover', false; }
    })
});

The galleriesListItem template:

<li class="span4">
    <div class="thumbnail">
        <a href="#">
            <img src="images/300x200.gif" alt="">
        </a>
        <div class="caption">
            <h4>{{view.content.name}}</h4>                        
            {{#if view.hover}}
                <button {{action editGallery view.content }} class="btn btn-mini" type="button">Edit</button>
                <button {{action deleteGallery view.content}} class="btn btn-mini" type="button">Delete</button>
            {{/if}}
        </div>
    </div>
</li>

I am not sure there is no error in my code, I just copy-paste and write how it should looks like.

Concerning the TODO you saw, this is because the Ember.CollectionView actually needs all the ember-handlebars module instead of just the file it needs, you should not care about that.

like image 33
louiscoquio Avatar answered Dec 18 '22 03:12

louiscoquio