Ember Components in brief – Ember.js Tutorial part 6

I’m using Ember 2.10.0 here.

After completing how to scaffold, template syntaxes, ember objects and routers in our Ember.js tutorial series; today in part 6 I will talk about one of the most important things in ember (even in front end programming); i.e. components.

Ember.View & Ember.Component

Before ember’s version 2.0, there used to be a View class (which is currently deprecated). There used to be a route which used to have it’s controller and under the controller there used to be view instances. A view used to have a template to render and it could also access the controller. The components of ember 2.0 are pretty similar to the Ember.View. The life cycle and methods etc are pretty similar, but unlike View, ember Components are isolated. It has a template for it and the actions triggered from the template is passed to the component object, but it doesn’t have or can access a controller and it doesn’t have a context. All data needs to be passed from outside.

Defining and using components

Though we can continue by using any other routes which we’ve created in last articles, but let’s create a fresh route and use a new component. So I will create a route named my-component-route and a component named student-details-component. Use the two commands below.

The first command will generate a route named my-component-route.js along with a template my-component-route.hbs. The second command will generate a component in app/components/ named student-details-component.js and a template for that with the same name in app/templates/components/.

First of all let’s provide the route (actually the controller) with a model. As I said we will cover Ember.Data in our upcoming articles, so now we will use simple object as model. Below is the code for my-component-route.js.

my-component-route.js

So the route is returning an array of students as model. Now let’s modify our student-details-component.js component as below.

student-details-component.js

Here we’ve added two properties firstName and lastName which we will provide from outside; and a computed property fullName. Now let’s code for the template of this component which is student-details-component.hbs.

student-details-component.hbs

So here, we’ve printed the fullName computed property that you can see. Just one line above that we’ve added a {{yield}} helper. This is kind of a placeholder whose html will be provided by the template which is using this component. I think after you see the my-component-route.hbs which is the template for our my-component-route route, you will have a better understanding of that {{yield}}.

my-component-route.hbs

In this code, first of all we’ve iterated the model, which we supplied in the router. Inside the {{each}} we’ve placed our newly created component student-details-component with two properties firstName and lastName provided from the model object. These two properties has been binded to the component’s firstName and lastName properties which helped to calculate the fullName property. The line This is details of student No: {{index}} is placed inside the component, so it will appear in the place where {{yield}} was used.

So if you run the ember app now, and navigate to localhost:4200/my-component-route you will find the following output.

ember-component-example

More how to’s of Ember components

How to pass data/property to the component

By the time you’ve already come to know, I think, about how to pass data or property to a component as the example above of my-component-route.hbs showed it. Yes, this is one way to pass the data. In this case you you are passing the properties as attribute of that component. However you can also send parameters basing on positions. Below is how to do it.

my-component-route.hbs

student-details-component.js

As you can see here, we passed the firstName and lastName as first and second parameter and then made the component to accept them using the property positionalParams. If you notice carefully, you will find I’ve put the positionalParams property in .reopenClass. The reason is, positionalParams is a static property to the class and can not be altered at runtime.

yield – the content wrapper

Yes you know about how {{yield}} works. We’ve used just a while ago. The content which you write inside the block of a component will appear in the {{yield}} part of that component. However if you do not have the necessity of {{yield}} or need of passing content, you can skip the # and the closing tag; and use your component as below.

Accessing component properties from wrapped content

You can also access any property which is defined inside your component from the wrapped code you’ve written. All you need to do is, pass that variable via the {{yield}} and hash helper; and using a as while implementing the component. Below is an example.

student-details-component.hbs

partial of my-component-route.hbs

Component elementName, attributes and class

If you check your DOM, you will find a Component’s output is always a div with a class=elber-view and no attribute. But ember provides you way to do more on these three.

element name

Changing the element name from div to something else (let’s p) is easy. The components has a property named tagName. You just need to override the value of it.

attributes

This is also easy. Hope just the example is enough to explain it.

The above code will result into following html.

class

There are couple of ways to provide className to your component. The easiest one is, while using it, you can directly give the class.

The second way is to provide the value of the property classNames as an array of strings inside the component.

In both the above cases it will add the my-dashing-class class in the DOM.
You can also add conditional classes. To do that you need to use the property classNameBindings. Below is an example.

It will automatically convert the camel case to dash case and myDashingClass will become my-dashing-class in the DOM and it will only appear if myDashingClass property is true.
You can even bind the classNames like if else statements. Below is an example.

If the property shouldIDisplay is true, it will add the class my-dashing-class in the DOM element, else your-dashing-class will be added.

DOM event handling

As components are the actual guys who will interact with the end user; and user interacts with events like click, doubleClick, drag etc etc. So for DOM events ember’s components have conventional hooks. I am adding a doubleClick() event on out student-details-component.js

Now if you double click on the component’s output in the browser, you will find the alert coming up. Just like doubleClick you can also use any of the following events.

  • touchStart
  • touchMove
  • touchEnd
  • touchCancel
  • keyDown
  • keyUp
  • keyPress
  • mouseDown
  • mouseUp
  • contextMenu
  • click
  • doubleClick
  • mouseMove
  • focusIn
  • focusOut
  • mouseEnter
  • mouseLeave
  • submit
  • change
  • focusIn
  • focusOut
  • input
  • dragStart
  • drag
  • dragEnter
  • dragLeave
  • dragOver
  • dragEnd
  • drop

You can also separately bind an action with any event. Below is an example.

In the template also there will be a change.

Component life cycle

Components are useful because they are completely isolated and due to there life cycle hooks, you know exactly when they are rendered and after that you can do anything with that piece of DOM. This gives you the power to control each part of the DOM through components. Below are the life cycle hooks of components.

Hooks

init(): This hook will be called at first. It’s just like constructor of your component class.

didReceiveAttrs(): This hook is called after the init, when the component’s properties are updated with the provided attributes. Both in case of first render and re-render due to attribute change this hook will be called.

willUpdate(): Will be called once the component is going to update itself. It will just be called in case of update and not on initial render.

willRender(): Both in case of first and re-render this hook will be called just before the rendering starts.

didInsertElement(): When the component is rendered to the DOM for the first time, this hook will be called.

didUpdate(): Will be called once the component has updated itself. It will just be called in case of update and not on initial render.

didRender(): After every render, be it the first one or the re-render, this hook will be called. Remember in case of first render it will be called after didInsertElement.

willDestroyElement(): As the name suggests, it will be called when the component is going to be destroyed. A component can be destroyed once you leave a route or due to if else conditions in the template.

willClearRender(): Called when the component is about to re-render, but before anything has been torn down. This is a good opportunity to tear down any manual observers you have installed based on the DOM state.

didDestroyElement(): Called after the component is destroyed.

Next part

So you are able to use components too now. Congratulations for that. In the next part of this Ember tutorial series, we will see what is Ember data and how models work.

About This Author

Hello! I am Paul Shan, a JavaScript Expert, Full Stack and DevOps Engineer cum Consultant based out of Bengaluru, India.