0

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.

2 Answers 2

1

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}}
Sign up to request clarification or add additional context in comments.

2 Comments

you sir are brilliant! First solution worked, I didn't know about itemController in the each. Any idea how I'd get Ember.Select's contentBinding to pull content from a function defined on ProductController?
I'm not sure what you mean, Ember.Select is inside the {{#each}}? Usually you would want to make that function a computed property list: function(){ return this.get('categories'); }.property('categories') and then contentBinding='list'
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.