Andrei Serdeliuc ॐ
Andrei Serdeliuc ॐ

Reputation: 5878

Ember.js arraycontroller call from view

I might be using this all wrong, but:

I've got an ArrayController representing a collection of products. Each product gets rendered and there are several actions a user could take, for example edit the product title or copy the description from a different product.

Question is: how do you interact with the controller for the specific product you're working with? How would the controller know which product was being edited?

I also tried to create an Ember.Select with selectionBinding set to "controller.somevar" but that also failed.

Upvotes: 0

Views: 226

Answers (2)

Andrew Hacking
Andrew Hacking

Reputation: 6366

If you define itemController on your ProductsController you don't need to specify that detail in your template:

App.ProductsController = Em.ArrayController.extend({
  itemController: 'product',
  needs: ['suppliers'],
  actions: {
    add: function() {
      // do something to add an item to content collection
    }
  } 
});

App.ProductController = Em.ObjectController.extend({
  actions: {
    remove: function() {
       // do something to remove the item
    }
  }
});

Use a collection template like this:

<button {{action="add"}}>Add Item</button>
<ul>
{{#each controller}}
  <li>{{name}} <button {{action="remove"}}>x</button></li>
{{/each}}
</ul>

The Ember documentation describesitemController here:

You can even define a function lookupItemController which can dynamically decide the item controller (eg based on model type perhaps).

The thing I found when rendering a collection wrapped in an ArrayController within another template/view is the way #each is used. Make sure you use {{#each controller}} as Teddy Zeeny shows otherwise you end up using the content model items and NOT the item controller wrapped items. You may not notice this until you try using actions which are intended to be handled by the item controller or other controller based content decoration.

When I need to nest an entire collection in another view I use the view helper as follows to set the context correctly so that any collection level actions (eg an add item button action) get handled by the array controller and not by the main controller setup by the route.

So in my products template I would do something like this to list the nested suppliers (assuming your route for 'product' has properly the 'suppliers' controller):

{{view controller=controllers.suppliers templateName="products/suppliers"}}

The suppliers template just follows the same pattern as the template I show above.

Upvotes: 0

Teddy Zeenny
Teddy Zeenny

Reputation: 3971

I think the most important thing you need to do, is first move as much logic as you can away from the views, and into controllers.

Another thing that would be useful in your case, is to have an itemController for each product in the list. That way, you can handle item specific logic in this item controller.

I don't have enough information to understand your architecture, so I will make a few assumptions.

Given you have the following ProductsController:

App.ProductsController = Ember.ArrayController.extend();

You need to create a ProductController that will be created to wrap every single product on its own.

App.ProductController = Ember.ObjectController.extend();

You need to modify your template as follows:

{{#each controller itemController="product"}}
  <li>name</li>
{{/each}}

Now every product in your list will have its own ProductController, which can handle one product's events and will act as the context for every list item.

Another option:

If you will only be handling one product at a time, you can use routes to describe which product you are working with:

App.Router.map(function() {
  this.resource('products', { path: '/products' }, function() {
    this.resource('product', { path: '/:product_id' }, function() {
      this.route('edit');
    });
  });
});

And create a controller for editing a product:

App.ProductEditController = Ember.ObjectController.extend();

And your list items would link to that product route:

{{#each controller}}
  <li>{{#linkTo "product.edit" this}}name{{/linkTo}}</li>
{{/each}}

Upvotes: 1

Related Questions