Object controller and array controller

Ember.js provides us with two types of controllers: Ember.ObjectController and Ember.ArrayController. We have been using Ember.ObjectController in many examples throughout this book. ObjectController works on one object and ArrayController works on an array or list of objects.

When we say that ObjectController works on a single object, we mean that the model property of the corresponding route returns the single JavaScript object and not an array. You can also use the setupController hook that was discussed in the previous chapter to set the model property of the controller. The default behavior of the setupController method is to set the model property on the controller to what is returned from the model method present in the route. So, you can either set the model in setupController or return the object from the model method present in the route.

ArrayController, on the other hand, has been designed to work on a list of items and hence the model, or the setupController hook, should set the model to an array of objects.

Let's see how can we use the ArrayController to display a list of products that is received from the server or similar.

The first thing we would need to do is to return an array of products from the model property of our corresponding route. Here, in our example, we will be using the products route to show the list of products:

import Ember from "ember";

export default Ember.Route.extend({
  model: function(){
    return[
      {
        "name":"Leather Jacket",
        "description":"A very long jacket description which cannot be shown inside a table and will have to be shortened",
        "currency":"USD",
        "symbol":"$",
        "price":"1999.999",
        "dimensions":{
          "length":7.0,
          "width":12.0,
          "height":9.5
        }
      },
      {
        "name":"Some Coat",
        "description":"A very long coat description which cannot be shown inside a table and will have to be shortened",
        "currency":"EURO",
        "symbol":"€",
        "price":"299.999",
        "dimensions":{
          "length":8.0,
          "width":11.0,
          "height":10.0
        }
      },
      {
        "name":"T Shirt",
        "description":"A very long T Shirt description which cannot be shown inside a table and will have to be shortened",
        "currency":"USD",
        "symbol":"$",
        "price":"58.999",
        "dimensions":{
          "length":9.0,
          "width":13.0,
          "height":11.0
        }
      },
      {
        "name":"White Shirt",
        "description":"A very long Shirt description which cannot be shown inside a table and will have to be shortened",
        "currency":"GBP",
        "symbol":"£",
        "price":"1999.9999",
        "dimensions":{
          "length":10.0,
          "width":14.0,
          "height":12.0
        }
      }
    ]
  }
});

The products route is present at app/routes/products.js

Here, we returned a static list of products from the model property of our route, but in most real-world cases, this would be fetched from the backend server. Here, each of our products has a name, description, currency, symbol, price, and dimensions property. The only issue is that the price is a floating point number and not a formatted number, so we will have to format the price and show it properly with the currency symbol. Also, the description that comes from the backend server is too long to be displayed in a table, so we will have to truncate that, as well.

Since most of the changes discussed above are related to the UI of the table, putting the functionality in the controller seems an obvious choice.

Let's look at the products controller:

import Ember from "ember";

export default Ember.ArrayController.extend({
  sortProperties: ['name'],
  sortAscending: true,
  itemController: 'product'
});

The products controller is present at app/controllers/products.js

As the products controller needs to work on a list of products, it should extend Ember.ArrayController. Ember.ArrayController includes the Ember.SortableMixin that implements the sorting of the items present in the model property of the controller. Ember.SortableMixin uses two properties to sort the underlying elements.

The first one is sortProperties, which contains an array of properties on which the items should be sorted. In our case, we sort the items in the table according to their names. The second property read by Ember.SortableMixin is sortAscending, which is a boolean variable which tells whether to use ascending order or descending order while sorting the elements.

Now, since ArrayController works on a complete array and not on individual items, the functionality to format date, description, and dimensions can't go in here. The products controller will contain properties that work on the array as a whole; for example, if we had to show how many products are above $50, we would add the computed property in the products controller.

For an individual item-specific transformation, the Ember.ArrayController can contain an itemController property, which should point to the controller that needs to be used for every item in the list. As you can see in the preceding code sample, we point itemController to the product. This tells the Ember.js framework to use product controller to decorate each of the item present in the model array.

Let's look at app/controllers/products/product.js, that is, the product controller that contains the computed properties decorating the original properties received from the severof individual items present in the model array:

import Ember from "ember";

export default Ember.ObjectController.extend({
  formattedPrice: function(){
    returnthis.get('symbol') + "   " + $.number(this.get('price'),2);
  }.property('symbol','price'),

  formattedDimension: function(){
    returnthis.get('dimensions.width') + " x " + this.get('dimensions.height') + " x " + this.get('dimensions.length'),
  }.property('dimensions.width','dimensions.height','dimensions.length'),

    shortDescription: function(){
      varshortDesc = this.get('description').substring(0, 25);
      returnshortDesc + "...";

  }.property('description')
});

Product controller is present at app/controllers/products/product.js

The product controller defined above extends Ember.ObjectController and works on an individual item of the array as its model property. Here, you can see that we have defined three computed properties: formattedPrice, formattedDimension, and shortDescription. These computed properties transform the data and make it presentable to the end user.

Now, since we have defined all the controllers and routes, the only thing left is to display the list of items in the products template. So, let's create the products template and present the products data in a tabular form, as shown in the following:

<h1> Products </h1>
<table class="table table-bordered">
  <thead>
    <tr>
      <th data-field="name">Item</th>
      <th data-field="description">Description</th>
      <th data-field="dimension">Dimension</th>
      <th data-field="price">Price</th>
    </tr>
    {{#each product in controller}}
    <tr>
      <td>{{product.name}}</td>
      <td>{{product.shortDescription}}</td>
      <td>{{product.formattedDimension}}</td>
      <td>{{product.formattedPrice}}</td>
      {{/each}}
    <tr>
  </thead>
</table>

The products template is present at app/templates/products.hbs

In the products.hbs template, we iterate over every item present in the products controller and present the transformed data from the product controller. itemController enables us to use {{product.shortDescription}} without much of configuration. This keeps the code clean and easy to understand.

If you go inside the chapter5/example1 directory and run ember serve, you will see the following output at http://localhost:4200:

Object controller and array controller

Presenting a list of products using Ember.ArrayController

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.144.65