Extending Ember.Component

Till now, we have been using Ember components in their default form. Ember.js lets you programmatically customize the component you are building by backing them with your own component JavaScript class.

Changing your component's tag

One of the most common use case for backing your component with custom JavaScript code is to wrap your component in a tag, other than the default <div> tag.

When you include a component in your template, the component is by default rendered inside a div tag. For instance, we included the copyright footer component in our application template using {{copyright-footer}}. This resulted in the following HTML code:

<div id="ember391" class="ember-view">
<footer>
    <div>
        © 20014-2015 Ember.js Essentials by Packt Publishing
    </div>
    <div>
        Content is available under MIT license
    </div>
</footer>
</div>

The copyright footer component HTML enclosed within a <div> tag

You can see that the copyright component's content is enclosed inside a div that has an ID ember391 and class ember-view. This works for most of the cases, but sometimes you may want to change this behavior to enclose the component in the enclosing tag of your choice. To do that, let's back our component with a matching component JavaScript class.

Let's take an instance in which we need to wrap the text in a <p> tag, rather than a <div> tag for the about us page of our application.

All the components of the JavaScript classes go inside the app/components folder. The file name of the JavaScript component class should be the same as the file name of the component's template that goes inside the app/templates/components/ folder.

For the above use case, first let's create a component JavaScript class, whose contents should be wrapped inside a <p> tag. Let us create a new file inside the app/components folder named about-us-intro.js, with the following contents:

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: "p"
});

The about-us component JavaScript class is present at chapter-7/example1/app/components/about-us-intro.js

As you can see, we extended the Ember.Component class and overrode the tagName property to use a p tag instead of the div tag.

Now, let us create the template for this component. The Ember.js framework will look for the matching template for the above component at app/templates/components/about-us-intro.hbs.

As we are enclosing the contents of the about-us-intro component in the <p> tag, we can simply write the about us introduction in the template as follows:

This is the about us introduction.Everything that is present here will be enclosed within a &lt;p&gt; tag.

The contents of chapter-7/example1/app/components/about-us-intro.hbs

We can now include the {{about-us-intro}} in our templates, and it will wrap the above text inside the <p> tag.

Now, if you visit the http://localhost:4200/about-us page, you should see the preceding text wrapped inside the <p> tag.

In the preceding example, we used a fixed tagName property in our component's class. But, in reality, the tagName property of our component could be a computed property in your controller or model class that uses your own custom logic to derive the tagName of the component:

import Ember from "ember";
export default Ember.ObjectController.extend({
  tagName: function(){
    //do some computation logic here
    return "p";
  }.property()
});

The about-us controller is present at chapter-7/example1/app/controllers/about-us.js

Then, you can override the default tagName property, with your own computed tagName from the controller:

{{about-us-intro tagName=tagName}}

For very simple cases, you don't even need to define your custom component's JavaScript class. You can override the properties such as tagName and others of your component when you use the component tag:

{{about-us-intro tagName="p"}}

Here, since you did not create a custom component class, the Ember.js framework generates one for you in the background, and then overrides the tagName property to use p, instead of div.

Adding custom CSS classes to your component

Similar to the tagName property of your component, you can also add additional CSS classes and customize the attributes of your HTML tags by using custom component classes.

To provide static class names that should be applied to your components, you can override the classNames property of your component. The classNames property if of type array should be assigned properties accordingly. Let's continue with the above example, and add two additional classes to our component:

import Ember from 'ember';

export default Ember.Component.extend({
    tagName: "p",
    classNames: ["intro","text"]
});

This will add two additional classes, intro and text, to the generated <p> tag.

If you want to bind your class names to other component properties, you can use the classNameBinding property of the component as follows:

export default Ember.Component.extend({
  tagName: "p",
  classNameBindings: ["intro","text"],
  intro: "intro-css-class",
  text: "text-css-class"
});

This will produce the following HTML for your component:

<p id="ember401" class="ember-view intro-css-class text-css-class">This is the about us introduction.Everything that is present here will be enclosed within a &lt;p&gt; tag.</p>

As you can see, the <p> tag now has additional intro-css-class and text-css-class classes added. The classNameBindings property of the component tells the framework to bind the class attribute of the HTML tag of the component with the provided properties of the component.

In case the property provided inside the classNameBindings returns a boolean value, the class names are computed differently. If the bound property returns a true boolean value, then the name of the property is used as the class name and is applied to the component. On the other hand, if the bound property returns to false, then no class is applied to the component.

Let us see this in an example:

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: "p",
  classNames: ["static-class","another-static-class"],
  classNameBindings: ["intro","text","trueClass","falseClass"],
  intro: "intro-css-class",
  text: "text-css-class",
  trueClass: function(){
    //Do Some logic
    return true;
  }.property(),
  falseClass: false
});

The about-us-intro component is present at chapter-7/example1/app/components/about-us-intro.js

Continuing with the above about-us-intro component, you can see that we have added two additional strings in the classNameBindings array, namely, trueClass and falseClass. Now, when the framework tries to bind the trueClass to the corresponding component's property, it sees that the property is returning a boolean value and not a string, and then computes the class names accordingly.

The above component shall produce the following HTML content:

<p id="ember401" class="ember-view static-class another-static-class intro-css-class text-css-class true-class">
  This is the about us introduction.Everything that is present here will be enclosed within a &lt;p&gt; tag.
</p>

Notice that in the given example, true-class was added instead of trueClass. The Ember.js framework is intelligent enough to understand the conventions used in CSS class names, and automatically converts our trueClass to a valid true-class.

Adding custom attributes to your component's DOM element

Till now, we have seen how we can change the default tag and CSS classes for your component. Ember.js frameworks let you specify and customize HTML attributes for your component's DOM (Document Object Model) element.

Many JavaScript libraries also use HTML attributes to provide additional details about the DOM element.

Ember.js framework provides us with attributeBindings to bind different HTML attributes with component's properties. The attributeBindings which is similar to classNameBindings, is also of array type and works very similarly to it.

Let's create a new component, called as {{ember-image}}, by creating a file at app/component/ember-image.js, and use attributes bindings to bind the src, width, and height attributes of the <img> tag.

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: "img",
  attributeBindings: ["src","height","width"],
  src: "http://emberjs.com/images/logos/ember-logo.png",
  height:"80px",
  width:"200px"
});

The ember-image component is present at chapter7/example1/app/components/ember-image.js

This will result in the following HTML:

<img
  id="ember401"
  class="ember-view"
  src="http://emberjs.com/images/logos/ember-logo.png"
  height="80px"
  width="200px">

There could be cases in which you would want to use a different component's property name and a different HTML attribute name. For those cases, you can use the following notation:

attributeBindings: ["componentProperty:HTML-DOM-property]
import Ember from 'ember';

export default Ember.Component.extend({
  tagName: "img",
  attributeBindings: ["componentProperty:HTML-DOM-property],
  componentProperty: "value"
});

This will result in the the following HTML code:

<img id="ember402" HTML-DOM-property="value">
..................Content has been hidden....................

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