Introduction
Welcome to the Ember Guide For Complete Beginners! These guides will teach you how to build ambitious web applications with the Ember.js framework.
This guide only assumes you have basic understanding of HTML, CSS and JavaScript.
Setting Up
Ember applications are most commonly built with a tool called Ember CLI, this tool helps you generate a new application, and also helps you with building, serving and testing your application.
Before you can install Ember CLI, you need to make sure you have Node.js and a Node package manager installed. We will use the Yarn package manager throughout the guides.
After you have installed Node.js and Yarn, we can install Ember CLI by running the following command:
yarn global add ember-cli
Installing Ember CLI adds the ember
command to your
terminal. With the ember
command you can generate a new
application:
ember new my-tutorial-app
If you run that command, it will generate an Ember application inside a
new folder called my-tutorial-app
. If you cd
into the folder, you can start working on your application.
cd my-tutorial-app
Now we can start Ember CLI's development server, so we can preview our changes in the browser:
ember serve
Running that command will output:
Livereload server on http://localhost:49152
Serving on http://localhost:4200/
Build successful - 8189ms.
Now you can visit http://localhost:4200/
in your browser,
you will be greeted by the following page:
Congratulations! You are now ready to start learning how to write Ember applications.
First Steps
Let's start by getting the application to show a friendly
Hello World
in the browser. To achieve this, we have to add
a Handlebars template to our
application. Handlebars templates look just like HTML, but with
handlebars expressions added. First we'll focus on the HTML part.
Templates are put in the app/templates
directory of your
Ember application. Every application needs a
application.hbs
to begin with. Let's add the following
app/templates/application.hbs
:
<h1>Hello World!</h1>
If you now look at http://localhost:4200/
, you should see
the following:
Adding a variable
Now let's add a expression to our template. Add the following to your
app/templates/application.hbs
template:
<p>Hello my name is {{name}}!</p>
If you look at the result, you'll see Hello my name is !
.
No name is being displayed. This is because the variable
name
has not been defined yet.
Where do the values of variables in a template come from? Templates belong to either a controller or a component. The properties of one of those are the variables you can display in your template. What either a controller or a component exactly is, will be explained later.
Instead of manually adding a file and filling in the basics, we'll use a generator to do this for us. Go ahead an run the following command in your terminal:
ember generate controller application
That command should output the following:
installing controller
create app/controllers/application.js
installing controller-test
create tests/unit/controllers/application-test.js
This means that it added two files to your project, one file is
the file for your actual controller, the second is the file where the
tests for your controller go. We'll ignore the test file for now and
take a look at the app/controllers/application.js
file:
import Ember from 'ember';
export default Ember.Controller.extend({
});
The controller file imports the Ember
variable and exports
a new sub-class of Ember.Controller
.
We can now add the name
property, this will make the
{{name}}
expression display the value of the
name
property.
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra'
});
If we now look at the result, we should see the name being displayed:
Adding a list of variables
Let's do something slightly more difficult. Let's add a list of our hobbies to the page.
We can start by adding the hobbies
property as an array of
strings to our application
controller:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra',
hobbies: ['Chess', 'Pinball', 'Hockey']
});
And also add something to the application
template to
display the hobbies:
<p>My hobbies are: {{hobbies}}</p>
As a result you'll see the following:
My hobbies are: Chess,Pinball,Hockey
As you can see, Ember is smart enough to display arrays as a comma
separated list. What if we want to do something a little more fancy?
For example, what if we want to display the hobbies in an
<ul>
list?
Let me introduce the each
expression for handlebars
templates. It looks like this:
{{#each hobbies as |hobby|}}
{{hobby}}
{{/each}}
The each expression takes your array of hobbies as argument and will yield each item in the array one by one. The part of the template within the each expression is rendered for each item in the given array.
Important to note is that the each
expression is in the
block form. A expression in block form starts with a #
sign
and the name of the expression. It ends with a /
and the
name of the expression.
The name between the vertical bars, |hobby|
, is a new
variable, that can only be used within the block expression. You can
give it any name you like.
Let's now change our application
template to use the
expression
to display the hobbies list:
<p>My hobbies are:</p>
<ul>
{{#each hobbies as |hobby|}}
<li>{{hobby}}</li>
{{/each}}
</ul>
If all went well, you should now see the following in your browser:
Computed Properties
Sometimes the properties on your controller aren't necissarily how you
want them to be displayed. Let's start with an example to demonstrate
this. Add the birthdate property to the application
controller:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra',
hobbies: ['Chess', 'Pinball', 'Hockey'],
birthdate: new Date(1984, 10, 21)
});
Now add the following HTML to the application
template:
<p>My birthdate is: {{birthdate}}</p>
As a result of this, you should see something like
My birthdate is on: Wed Nov 21 1984 00:00:00 GMT+0100 (CET)
in the browser.
The result gets the point across, but we propably meant to display
something simpler like Wed Nov 21 1984
, because the time
and timezone are irrelevant to a birthdate
We can use a Computed Property to achieve the desired result. Computed properties are functions that use other properties and return a new value based on those properties. Computed properties need to declare which properties they depend on. This way Ember can lazily evaluate the computed property function when it detects that one or more of the properties it depends on has changed.
Let's look at an example computed property that returns the date as a string in the format that we want it to be:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra',
hobbies: ['Chess', 'Pinball', 'Hockey'],
birthdate: new Date(1984, 10, 21),
birthdateFormatted: Ember.computed('birthdate', function() {
return this.get('birthdate').toDateString();
})
});
If you look at the birthdateFormatted
property, you'll
notice that we are using the Ember.computed
function to
create the computed property. The first argument that we pass to that
function is 'birthdate'
, this is how you declare that the
computed property depends on the birthdate
property. The
second argument is a function that computes a nicely formatted date from
the birthdate
property. The function will be evaluated
every time birthdate
changes.
You might also have noticed that the function to compute
birthdateFormatted
uses the this.get
function.
In this case using this.birthdate
would have worked, but if
the property we wanted to retrieve was a computed property, that
wouldn't work. It's an Ember convention to use get
to
retrieve the value of any property from an object.
Lastly we should also not forget to update the template to use
{{birthdateFormatted}}
instead of just
{{birthdate}}
. The result of that should look like the
following:
Adding interactivity
Chances are, that you want your users to be able to interact with your app. For example, make something happen when a users clicks on a button or fills in a form field. Ember calls these type of interactions 'actions'.
Let's try to add a simple button that adds one to a number everytime you
click on it. First we'll set up the controller with a
clicks
property and make the template display the clicks
value and a button. Starting with the controller:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra',
hobbies: ['Chess', 'Pinball', 'Hockey'],
clicks: 0
});
And add the following to the template:
<p>Clicks: {{clicks}}</p>
<button>Click me</button>
Now the page should display Clicks: 0
and a button stating
Click me
, but if you click the button, nothing happens.
Let's make something happen using an Ember action. This is done using
the action
expression in your handlebars template. The
controller belonging to the template will also need a function handling
that action.
We want the action to happen when the button is clicked, so we need to
set the onclick
attribute of the button with the action
expression. Update the HTML for the button to the following:
<button onclick={{action "buttonClicked"}}>Click me</button>
The string argument to the action
is the name of the action
we want to call on the corresponding controller. Actions are looked up
as functions inside the actions
property. Here's how it
looks in our example:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marten Schilstra',
hobbies: ['Chess', 'Pinball', 'Hockey'],
clicks: 0,
actions: {
buttonClicked() {
let clicks = this.get('clicks');
this.set('clicks', clicks + 1);
}
}
});
If you now click on the button, the number of clicks displayed increases by one.
Keen observers will have noticed that the action function in the
controller contains this.set
. Just like
this.get
to retrieve values of properties, you need
this.set
to update a property's value.