Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Templates intro #477

Merged
merged 16 commits into from
Mar 7, 2019
216 changes: 173 additions & 43 deletions guides/release/templates/handlebars-basics.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,215 @@
Ember uses a templating language based on [Handlebars templating library](http://www.handlebarsjs.com) to power your app's user interface.
Ember templates contain static HTML and dynamic content inside Handlebars expressions, which are invoked with double curly braces: `{{}}`.
Templates are the home for what the user sees, like forms, buttons, links, and headings.

In this section of the Guides, you will learn about where to write HTML markup, plus how to add interaction, dynamically changing content, styling, and more.
If you want to learn in a step-by-step way, you should begin your journey in the [Tutorial](../../tutorial/ember-cli/) instead.

### Displaying Properties
## Writing plain HTML

Templates are backed with a context. A context is an object from which
Handlebars expressions read their properties. In Ember this is often a component. For templates rendered by a route (like `application.hbs`), the context is a controller.
Ember templates have some superpowers, but let's start with regular HTML.
For any file in an Ember app that has an extension ending in `.hbs`, you can write HTML markup in it as if it was an `.html` file.
HTML is the language that browsers understand for laying out content on a web page.
`.hbs` stands for Handlebars, the name of a tool that lets you write more than just HTML in your templates.

For example, this `application.hbs` template will render a first and last name:
For example, every Ember app has a file called `application.hbs`.
You can write regular HTML markup there or in any other `hbs` file:

```handlebars {data-filename=app/templates/application.hbs}
Hello, <strong>{{this.firstName}} {{this.lastName}}</strong>!
```handlebars {data-filename=app/templates/application.hbs data-update=false}
<h1>Starting simple</h1>
<p>
This is regular html markup inside an hbs file
</p>
```

The `firstName` and `lastName` properties are read from the
context (the application controller in this case), and rendered inside the
`<strong>` HTML tag.
When you start an app with `ember serve`, the compiler may help you catch some errors, such as forgetting to close a tag or missing a quotation mark.
Reading the error message on the page or in your browser's developer console will get you back on track.

## Types of templates

There are two main types of templates: Route templates and Component templates.

A Route template determines what is shown when someone visits a particular URL, like `https://guides.emberjs.com/some-route`.
A Component template has bits of content that can be reused in multiple places throughout the app, like buttons or forms.

If you look at an existing app, you will see templates in many different places in the app folder structure!
This is to help the app stay organized as it grows from one template to _one hundred_ templates.
The best way to tell if a template is part of a Route or Component is to look at the file path.

## Making new templates

New templates should be made using [Ember CLI](https://cli.emberjs.com) commands.
The CLI helps ensure that the new files go in the right place in the app folder structure, and that they follow the essential file naming conventions.

For example, either of these commands will generate `.hbs` template files (and other things!) in your app:

```sh
ember generate component my-component-name
ember generate route my-route-name
```

To provide a `firstName` and `lastName` to the above template, properties
must be added to the application controller. If you are following along with
an Ember CLI application, you may need to create this file:
## Template restrictions

A typical, modern web app is made of dozens of files that have to all be combined together into something the browser can understand.
Ember does this work for you with zero configuration, but as a result, there are some rules to follow when it comes to adding assets into your HTML.

You cannot use script tags directly within a template, and should use [actions](../actions/) or [Component Lifecycle Hooks](../../components/the-component-lifecycle/) to make your app responsive to user interactions and new data.
If you are working with a non-Ember JavaScript library and need to use a `js` file from it, see the Guide section [Addons and Dependencies](../../addons-and-dependencies/managing-dependencies/).

You should not add links to your own local CSS files within the `hbs` file.
Style rules should go in the `app/styles` directory instead.
`app/styles/app.css` is included in your app's build by default.
For CSS files within the styles directory, you can create multiple stylesheets and use regular CSS APIs like `import` to link them together.
If you want to incorporate CSS from an npm package or similar, see [Addons and Dependencies](../../addons-and-dependencies/managing-dependencies/) for instructions.
To load styles through a CDN, read the next section below.

## What is `index.html` for?

If HTML markup goes in `hbs` templates, what is `index.html` for?

The `index.html` file is the entry point for an app.
It is not a template, but rather it is where all the templates, stylesheets, and JavaScript come together into something the browser can understand.

When you are first getting started in Ember, you will not need to make any changes to `index.html`.
There's no need to add any links to other Ember app pages, stylesheets, or scripts in here by hand, since Ember's built-in tools do the work for you.

A common customization developers make to `index.html` is adding a link to a CDN that loads assets like fonts and stylesheets.
Here's an example:

```html {data-filename=app/index.html}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/index.html -> src/ui/index.html

<link integrity="" rel="stylesheet" href="https://my-font-cdn/something.css">
```

```javascript {data-filename=app/controllers/application.js}
import Controller from '@ember/controller';
## Understanding a Template's context

export default Controller.extend({
A template only has access to the data it has been given.
This is referred to as the template's "context."
For example, to display a property inside a Component's template, it should be defined in the Component's JavaScript file:

```javascript {data-filename=app/components/my-component.js}
import Component from '@ember/component';

export default Component.extend({
firstName: 'Trek',
lastName: 'Glowacki'
lastName: 'Glowacki',
favoriteFramework: 'Ember'
});
```

The above template and controller render as the following HTML:
Properties like `firstName` can be used in the template
by putting them inside of curly braces, plus the word
`this`:

```handlebars {data-filename=app/templates/application.hbs}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/templates/application.hbs -> src/ui/routes/application/template.hbs

Hello, <strong>{{this.firstName}} {{this.lastName}}</strong>!
```

Together, these render with the following HTML:

```html
Hello, <strong>Trek Glowacki</strong>!
```

Remember that `{{this.firstName}}` and `{{this.lastName}}` are bound data. That means
if the value of one of those properties changes, the DOM will be updated
automatically.
## Things you might see in a template

A lot more than just HTML markup can go in templates.
In the other pages of this guide, we will cover the features one at a time.
In general, special Ember functionality will appear inside curly braces, like this: `{{example}}`.
Here are a few examples of Ember Handlebars in action:

Route example:
```handlebars {data-filename=app/templates/application.hbs data-update=true}

<!-- outlet determines where a child route's content
should render. Don't delete it until you know more
about it! -->
<div>
{{outlet}}
</div>

<!-- One way to use a component within a template -->
<MyComponent />

{{! Example of a comment that will be invisible, even
if it contains things in {{curlyBraces}} }}

```

Component example:

```handlebars {data-filename=app/components/templates/my-component.hbs data-update=true}
<!-- A property that is defined in a component's
JavaScript file -->
{{this.numberOfSquirrels}}

<!-- Some data passed down from a parent component
or controller -->
{{weatherStatus}}

<!-- This button uses Ember Actions to make it interactive.
A method named `plantATree` is called when the button is
clicked. `plantATree` comes from the JavaScript file
associated with the template, like a Component or
Controller -->
<button onclick={{action 'plantATree'}}>
More trees!
<button>

<!-- Here's an example of template logic in action.
If the `this.skyIsBlue` property is `true`, the text
inside will be shown -->
{{#if this.skyIsBlue}}
If the skyIsBlue property is true, show this message
{{/if}}

<!-- You can pass a whole block of markup and handlebars
content from one component to another. yield is where
the block shows up when the page is rendered -->
{{yield}}
```
jenweber marked this conversation as resolved.
Show resolved Hide resolved

Lastly, it's important to know that arguments can be passed from one Component to another through templates:

As an application grows in size, it will have many templates backed by
controllers and components.
```handlebars {data-filename=app/templates/some-other-component.hbs}
<MyComponent @favoriteFramework=this.favoriteFramework />
```

### Helpers
To pass in arguments associated with a Route, define the property from within a Controller. Learn more about passing data between templates [here](../../components/passing-properties-to-a-component).

Ember Helpers are functions that can compute values and can be used in any template.
## Helper functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to split this out ssooo bad.


Ember gives you the ability to [write your own helpers](../writing-helpers/), to bring a minimum of logic into Ember templating.
Ember Helpers are a way to use JavaScript logic in your templates.
For example, you could write a Helper function that capitalizes a word, does some math, converts a currency, or more.
A Helper takes in `parameters`, which is an array of the values passed into the function, and should return a value.
Ember gives you the ability to [write your own helpers](../writing-helpers/), and comes with some [helpers built-in](../built-in-helpers).

For example, let's say you would like the ability to add a few numbers together, without needing to define a computed property everywhere you would like to do so.
For example, let's say you would like the ability to add two numbers together.
Define a function in `app/helpers/sum.js` to create a `sum` helper:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/helpers/sum.js -> src/ui/components/sum.js


```javascript {data-filename=app/helpers/sum.js}
import { helper } from '@ember/component/helper';
import { helper as buildHelper } from '@ember/component/helper';

export function sum(params) {
return params.reduce((a, b) => {
return a + b;
});
return params[0] + params[1]
};

export default helper(sum);
export const helper = buildHelper(sum);
```

The above code will allow you invoke the `sum()` function as a `{{sum}}` handlebars "helper" in your templates:
Now you can use the `sum()` function as `{{sum}}` in your templates:

```handlebars {data-filename=app/templates/application.hbs}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/templates/application.hbs -> src/routes/application/template.hbs

<p>Total: {{sum 1 2 3}}</p>
<p>Total: {{sum 1 2}}</p>
```

This helper will output a value of `6`.
The user will see a value of `3` rendered in the template!

Ember ships with several built-in helpers, which you will learn more about in the following guides.

#### Nested Helpers

Helpers have the ability to be nested within other helper invocations and also component invocations.

This gives you the flexibility to compute a value _before_ it is passed in as an argument or an attribute of another.
### Nested Helpers

It is not possible to nest curly braces `{{}}`, so the correct way to nest a helper is by using parentheses `()`:
Sometimes, you might see helpers used inside of some parentheses, `()`.
It means that a Helper is being used inside of another Helper or Component.
This is referred to as a "nested" Helper.
Parentheses must be used because curly braces `{{}}` cannot be nested.

```handlebars {data-filename=app/templates/application.hbs}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/templates/application.hbs -> src/routes/application/template.hbs

{{sum (multiply 2 4) 2}}
Expand All @@ -91,4 +221,4 @@ Thus, the output of these combined helpers is `10`.

As you move forward with these template guides, keep in mind that a helper can be used anywhere a normal value can be used.

Thus, many of Ember's built-in helpers (as well as your custom helpers) can be used in nested form.
Many of Ember's built-in helpers (as well as your custom helpers) can be used in nested form.