Skip to content

10.0.0 belongsTo Association

Patrick Baselier edited this page Oct 22, 2015 · 13 revisions

What you will learn

  • Define and render a belongsTo association
  • Use query-params to filter a list
  • Update the belongsTo association

Before you start

See the installation instructions. Use tag 10.0.0.

Render category

Open frontend/app/templates/products.hbs and update the code as follows to show the category's name:

...
<p class='badge'>{{product.categoryName}}</p>
<p>{{product.description}}</p>
...
  • Make the same changes to frontend/app/templates/products/show.hbs:
...
<p class='badge'>{{model.categoryName}}</p>
<p>{{model.description}}</p>
...
  • Open frontend/app/models/product.js and add a category association and a method for its name:
export default DS.Model.extend({
  ...
  reviews: DS.hasMany('review'),
  category: DS.belongsTo('category', { async: false }),
  categoryName: Ember.computed('category', function() {
    return this.get('category.name');
  })
});
  • Inspect the error shown in the Console tab in the browser. Ember doesn't know the category model yet. Let's define it.
  • In the frontend folder, enter the command ember g model category.
  • Open frontend/app/models/category.js and add the following attributes:
export default DS.Model.extend({
  name: DS.attr()
})

Show categories in navigation

Open frontend/app/templates/products.hbs and replace the <a> tags within <div class='content-navigation'> with:

{{#each uniqCategories as |category|}}
  {{#link-to 'products' class='list-group-item'}}{{category.name}}{{/link-to}}
{{/each}}
  • Open frontend/app/controllers/products.js and add the following properties:
export default Ember.Controller.extend({
  ...
  categories: Ember.computed.mapBy('model', 'category'),
  uniqCategories: Ember.computed.uniq('categories')
});

Filter on category

Open frontend/app/templates/products.hbs and add a query-param to the {{link-to}} helper:

{{#link-to 'products' (query-params category=category.name) class='list-group-item'}}
  • Open frontend/app/controllers/products.js, add the queryParams property and update the filteredContent function so that it uses the category value for displaying the proper products:
export default Ember.Controller.extend({
  ...
  queryParams: ['category'],
  category: '',
  ...
  filteredContent: Ember.computed(..., 'category', function() {
    var products = this.model,
        search = new RegExp(this.get('search'), 'i'),
        category = this.get('category');

    products = products.filter(function(product) {
      var str = product.get('title') + product.get('description');
      return search.test(str);
    });

    if (category) {
      products =  products.filterBy('category.name', category);
    }

    return products;
  }),
  ...
});
  • Open frontend/app/templates/application.hbs and update the {{link-to}} helper to reset the filter:
{{#link-to 'products' (query-params category='')}}Products{{/link-to}}

Show products counter

  • Open frontend/app/templates/products.hbs and add markup to show the number of products per category. Change:
{{#link-to 'products' (query-params category=category.name) class='list-group-item'}}{{category.name}}{{/link-to}}

to

{{#link-to 'products' (query-params category=category.name) class='list-group-item'}}{{category.name}}<small> ({{category.products.length}})</small>{{/link-to}}
  • Open frontend/app/models/category.js and add the following property:
export default DS.Model.extend({
  ...
  products: DS.hasMany('product')
});

Edit belongsTo Association

  • In the terminal, from the frontend folder enter ember install emberx-select
  • Open frontend/app/templates/products/show.hbs and, within the form between the price and image add the following code:
<div class='form-group'>
  {{#x-select value=model.category.id  action='selectCategory' class='form-control'}}
    {{#each categories as |category|}}
      {{#x-option value=category.id}}
        {{category.name}}
      {{/x-option}}
    {{/each}}
  {{/x-select}}
</div>

The ProductsShowController does not have a property categories yet, so let's add it. We also will add the setCategory action for updating the product.

  • Open frontend/app/controllers/products/show.js and add the following properties:
export default Ember.Controller.extend({
  categories: Ember.computed(function() {
    return this.store.peekAll('category');
  }),
  actions: {
    ...
    selectCategory(value) {
      this.model.set('category', this.store.peekRecord('category', value));
    }
  }
});

As you might notice, currently when you edit a product, the Update button will not get enabled when you select another category. This is because the model does not get marked as dirty when an association changed. I think this is a bug that definitely has some workarounds, but are not applied here.