Chapter 7. Building Reusable Components

In the last chapter, we learned about the ember-data library. We learned how easily and effectively the ember-data library design patterns streamline, and how the application talks with the backend API. In this chapter, we will focus on building reusable view components using Ember.js views and component classes.

In this chapter, we shall cover:

  • Introducing Ember views and components:
    • Custom tags with Ember.Component
    • Defining your own components
    • Passing data to your component
  • Providing custom HTML to your components
  • Extending Ember.Component:
    • Changing your component's tag
    • Adding custom CSS classes to your component
    • Adding custom attributes to your component's DOM element
  • Handling actions for your component
  • Mapping component actions to the rest of your application

Introducing Ember views and components

In Chapter 3, Rendering Using Templates we learned about handlebars templates and how we can use the Handlebars.js to create data-bound templates. Most of the time, Handlebars.js templates will be enough to create simple applications. But when working on a big, complex application, we are much likely to run into situations in which we can see that we are duplicating a lot of code in handlebars.js templates and repeated handling similar UI events in different controllers of our applications.

In order to tackle the problem of code duplicity and complex event handling of UI elements at one place, Ember.js provides us with two options; components and views. Components and views in Ember.js encapsulate templates, and lets us reuse the abstraction at different places in our application.

Views in Ember.js encapsulate the template and its actions. They have implicit access to the context that the views are being used in. As a result, you can easily access the associated controller and model properties from the view class.

Components, on the other hand, were introduced in Ember in 1.0 RC6 (http://emberjs.com/blog/2013/06/23/ember-1-0-rc6.html). Components, as opposed to views, are totally unaware of the context they are being used in. They don't have access to the enclosing controller, route, or model and require all the data to be passed explicitly to them. This makes the reusability of Ember.js components much better than views. Ember.js components are designed to be reusable, not just within your application, but even across different applications.

Since components were introduced in Ember.js framework, there has been a lot of confusion regarding when to use components and when to use views. Initially, the Ember.js framework contained only the Ember.View class and all the encapsulation and event handling was done inside it, but when Ember.Component was introduced, it was introduced to fix the broken abstraction present in Ember.js views.

Since then, the framework and the community have been pushing to use Ember.Component instead of extending Ember.View. Even the Ember 2.0 roadmap focuses more on components than it does on views.

As a result, views should be treated as more of an internal implementation detail of Ember.js framework. Views in Ember.js power {{if}}, {{outlet}}, and many other Handlebars.js helper methods. You should work more with views if you are creating a new Ember.js element, Handlebar.js helper, or are working on a framework of yours that runs alongside Ember.js.

Because of this shift of the framework toward Ember.Component, the focus of this chapter will be on Ember components and it will be left to readers to explore ember views for themselves.

Custom tags with Ember.Component

Till now, we have been using built-in HTML tags such as body, tr, td, div, and so on in our application. Wouldn't it be nice if a framework could allow you to build application-specific tags whose behavior and actions could be handled using JavaScript? Ember.js Ember.Component lets you do that. In fact, the W3C group, which defines the web standards, is already working on a very similar web component specification that would allow you to define custom application-specific HTML tags. Once browsers support custom components, you should be able to easily migrate your Ember.Component class to the W3C standards.

Defining your own components

The simplest way to define you Ember component is to create a new template file in the app/templates/components/ folder. In order to resolve the components automatically, the Ember.js framework makes it mandatory for the name of the component's file to include a -. Hence, address is an invalid component and person-address is a valid one.

A very common requirement of web applications is to include a copyright footer. Let's create a component to include the company's copyright footer in their application:

  1. The first thing to do is to create a new file in app/templates/components directory called as copyright-footer.hbs, with the following contents:
    <footer>
      <div>
        © 20014-2015 Ember.js Essentials by Packt Publishing
      </div>
      <div>
        Content is available under MIT license
      </div>
    </footer>

    The copyright-footer.hbs is present at chapter7/example1/app/templates/components/copyright-footer.hbs

  2. To use the above component, we can now include the {{copyright-footer}} in our templates and that would render the copyright footer there.
  3. Let's add the component in our application.hbs file, present at app/templates/:
    <h2 id='title'>Welcome to Ember.js</h2>
    
    {{outlet}}
    {{copyright-footer}}

    The application.hbs is present at chapter7/example1/app/templates/application.hbs

This will result in the copyright footer being present in all the pages of our application.

Passing data to your component

Till now, we saw the case wherein there was static data in our component templates, but to make components reusable, it often requires that some data of the component be made configurable and is passed in to it. This is also one of the main advantages of using components: if you pass in the correct configuration of the components, it works correctly no matter which place the component is included in.

Let's create a new component called as product-description, which displays the product data passed into it:

  1. For that, let's create a file named product-description.hbs at app/templates/components/ directory. This template file will contain the components of the product description. Since the data for product specification template changes with the product, this data should be passed in while using the component.
  2. When building this template, we can assume that this data will be passed in explicitly, and will be accessible using standard handlebars syntax.
    <h4>
      <span> {{name}} </span>
    </h4>
    <div>
      <table>
        <tr>
          <td> M.R.P </td>
          <td> {{MRP}}</td>
        </tr>
        <tr>
          <td> Price </td>
          <td> {{price}}</td>
        </tr>
        <tr>
          <td> You Save </td>
          <td> {{sale}} </td>
        </tr>
      </table>
    </div>

    The product description component is present at chapter7/example1/app/templates/components/product-description.hbs

    As you can see, we have made name, MRP, price, and sale of a product configurable, and should be passed in explicitly when using the component.

  3. Now in order to pass in the data to a component, we can simply do like the following code snippet:
    {{product-description name="Product Name"  MRP="$ 100" price="$80" sale="$20"}}

    You could also fetch the MRP, price, and sale property from your route's model object as follows:

    {{#product-description name="Product Name"  MRP=model.MRP price=model.price sale=model.sale}}

    The model can return the appropriate object by either fetching it from the server, or returning a static object as follows:

    import Ember from 'ember';
    
    export default Ember.Route.extend({
      model: function(){
        return { MRP:"$ 100",price:"$80",sale:"$20"};
      }
    });

    The index route returning a static model object is present at chapter7/example1/app/routes/index.js

  4. If you run the example and visit http://localhost:4200/ on your machine, you will see something like the following:
    Passing data to your component

    The Index page for example1 including product description and copyright-footer components

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

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