Skip to content
This repository has been archived by the owner on May 26, 2019. It is now read-only.

Rewrote components to cli in the guide #18

Merged
merged 22 commits into from
Mar 18, 2015
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions source/components/customizing-a-components-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ To use a tag other than `div`, subclass `Ember.Component` and assign it
a `tagName` property. This property can be any valid HTML5 tag name as a
string.

```js
App.NavigationBarComponent = Ember.Component.extend({
```app/components/navigation-bar.js
export default Ember.Component.extend({
tagName: 'nav'
});
```

```handlebars
{{! templates/components/navigation-bar }}
```templates/components/navigation-bar.hbs
<ul>
<li>{{#link-to 'home'}}Home{{/link-to}}</li>
<li>{{#link-to 'about'}}About{{/link-to}}</li>
Expand All @@ -37,8 +36,8 @@ App.NavigationBarComponent = Ember.Component.extend({
You can also specify which class names are applied to the component's
element by setting its `classNames` property to an array of strings:

```javascript
App.NavigationBarComponent = Ember.Component.extend({
```app/components/navigation-bar.js
export default Ember.Component.extend({
classNames: ['primary']
});
```
Expand All @@ -47,8 +46,8 @@ If you want class names to be determined by properties of the component,
you can use class name bindings. If you bind to a Boolean property, the
class name will be added or removed depending on the value:

```js
App.TodoItemComponent = Ember.Component.extend({
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['isUrgent'],
isUrgent: true
});
Expand All @@ -65,8 +64,8 @@ If `isUrgent` is changed to `false`, then the `is-urgent` class name will be rem
By default, the name of the Boolean property is dasherized. You can customize the class name
applied by delimiting it with a colon:

```javascript
App.TodoItemComponent = Ember.Component.extend({
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['isUrgent:urgent'],
isUrgent: true
});
Expand All @@ -80,8 +79,8 @@ This would render this HTML:

Besides the custom class name for the value being `true`, you can also specify a class name which is used when the value is `false`:

```javascript
App.TodoItemComponent = Ember.Component.extend({
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['isEnabled:enabled:disabled'],
isEnabled: false
});
Expand All @@ -96,8 +95,8 @@ This would render this HTML:
You can also specify a class which should only be added when the property is
`false` by declaring `classNameBindings` like this:

```javascript
App.TodoItemComponent = Ember.Component.extend({
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['isEnabled::disabled'],
isEnabled: false
});
Expand All @@ -118,8 +117,8 @@ If the `isEnabled` property is set to `true`, no class name is added:
If the bound property's value is a string, that value will be added as a class name without
modification:

```javascript
App.TodoItemComponent = Ember.Component.extend({
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['priority'],
priority: 'highestPriority'
});
Expand All @@ -136,8 +135,8 @@ This would render this HTML:
You can bind attributes to the DOM element that represents a component
by using `attributeBindings`:

```javascript
App.LinkItemComponent = Ember.Component.extend({
```app/components/link-item.js
export default Ember.Component.extend({
tagName: 'a',
attributeBindings: ['href'],
href: "http://emberjs.com"
Expand All @@ -146,20 +145,20 @@ App.LinkItemComponent = Ember.Component.extend({

You can also bind these attributes to differently named properties:

```javascript
App.LinkItemComponent = Ember.Component.extend({
```app/components/link-item.js
export default Ember.Component.extend({
tagName: 'a',
attributeBindings: ['customHref:href'],
customHref: "http://emberjs.com"
});
```

### Example
<!-- ### Example

Here is an example todo application that shows completed todos with a
red background:

<a class="jsbin-embed" href="http://jsbin.com/duzala/1/embed?live">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>

**Note:** The binding functionality in this very simple example could also be implemented without
the use of `Ember.Component` but by simply [binding element attributes](../../templates/binding-element-attributes) or [binding element class names](../../templates/binding-element-class-names).
the use of `Ember.Component` but by simply [binding element attributes](../../templates/binding-element-attributes) or [binding element class names](../../templates/binding-element-class-names). -->
64 changes: 45 additions & 19 deletions source/components/defining-a-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,57 @@ create a `components/blog-post` template.
but `post` is not. This prevents clashes with current or future HTML element names, and
ensures Ember picks up the components automatically.

If you are including your Handlebars templates inside an HTML file via
`<script>` tags, it would look like this:

```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>Blog Post</h1>
<p>Lorem ipsum dolor sit amet.</p>
</script>
```
A sample component template would look like this:

If you're using build tools, create a Handlebars file at
`templates/components/blog-post.handlebars`.
```app/components/blog-post.hbs
Copy link
Member

Choose a reason for hiding this comment

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

app/templates/components/blog-post.hbs

<h1>Blog Post</h1>
<p>Lorem ipsum dolor sit amet.</p>
```

Having a template whose name starts with `components/` creates a
component of the same name. Given the above template, you can now use the
`{{blog-post}}` custom element:
<!--- <a class="jsbin-embed" href="http://jsbin.com/tikenoniku/1/edit?output">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>

The example above uses `<script>` tags to work inside of JSBin.-->

```handlebars
<h1>My Blog</h1>
{{#each post in model}}
{{blog-post}}
```app/templates/index.hbs
{{#each}}
{{#blog-post title=title}}
{{body}}
{{/blog-post}}
{{/each}}
```

<a class="jsbin-embed" href="http://jsbin.com/juvic/embed?js,output">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>
```app/templates/components/blog-post.hbs
<article class="blog-post">
<h1>{{title}}</h1>
<p>{{yield}}</p>
<p>Edit title: {{input type="text" value=title}}</p>
</article>
```

```app/routes/index.js
var posts = [{
title: "Rails is omakase",
body: "There are lots of à la carte software environments in this world."
}, {
title: "Broken Promises",
body: "James Coglan wrote a lengthy article about Promises in node.js."
}];

export default Ember.Route.extend({
model: function() {
return posts;
Copy link
Member

Choose a reason for hiding this comment

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

missing spaces

Copy link
Member

Choose a reason for hiding this comment

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

thoughts on inling the posts object in the model hook?

Copy link
Member

Choose a reason for hiding this comment

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

Indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure how the indentation should look?

Copy link
Member

Choose a reason for hiding this comment

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

export default Ember.Route.extend({
  model: function() {
    return posts;
  }
});

}
});
```

```app/components/blog-post.js
export default Ember.Component.extend({

});
```

Each component, under the hood, is backed by an element. By default
Ember will use a `<div>` element to contain your component's template.
Expand All @@ -55,9 +81,9 @@ changes to the component's element using JavaScript.

Ember knows which subclass powers a component based on its name. For
example, if you have a component called `blog-post`, you would create a
subclass called `App.BlogPostComponent`. If your component was called
`audio-player-controls`, the class name would be
`App.AudioPlayerControlsComponent`.
a file at `app/components/blog-post.js`. If your component was called
Copy link
Member

Choose a reason for hiding this comment

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

It looks from the diff that this will end up reading "you would create a a file", but I could be mis-reading the diff. Can you double check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ooops

`audio-player-controls`, the file name would be at
`app/components/audio-player-controls.js`

In other words, Ember will look for a class with the camelized name of
the component, followed by `Component`.
Expand Down
19 changes: 9 additions & 10 deletions source/components/handling-user-interaction-with-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,24 @@ bubble.
For example, imagine the following component that shows a post's title.
When the title is clicked, the entire post body is shown:

```handlebars
<script type="text/x-handlebars" id="components/post-summary">
<h3 {{action "toggleBody"}}>{{title}}</h3>
{{#if isShowingBody}}
<p>{{{body}}}</p>
{{/if}}
</script>
```app/templates/components/post-summary.js
Copy link
Member

Choose a reason for hiding this comment

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

This should be .hbs not .js.

<h3 {{action "toggleBody"}}>{{title}}</h3>
{{#if isShowingBody}}
<p>{{{body}}}</p>
{{/if}}
```

```js
App.PostSummaryComponent = Ember.Component.extend({
```app/components/post-summary.js
export default Ember.Component.extend({
actions: {
toggleBody: function() {
this.toggleProperty('isShowingBody');
}
}
});
```
<a class="jsbin-embed" href="http://jsbin.com/yuzena/embed?live">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>

<!---<a class="jsbin-embed" href="http://jsbin.com/ciwenemedi/1/embed?live">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>-->

The `{{action}}` helper can accept arguments, listen for different event
types, control how action bubbling occurs, and more.
Expand Down
45 changes: 44 additions & 1 deletion source/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,47 @@ To highlight the power of components, here is a short example of turning a blog
application. Keep reading this section for more details on building
components.

<a class="jsbin-embed" href="http://jsbin.com/juvic/embed?js,output">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>
<!---<a class="jsbin-embed" href="http://jsbin.com/xexumomaru/1/embed?live">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>

The example above uses `<script>` tags to work inside of JSBin. Ember-cli works by file structure, so there are no `<script>` tags:-->

```app/templates/index.hbs

{{#each}}
{{#blog-post title=title}}
{{body}}
{{/blog-post}}
{{/each}}
```

```app/templates/components/blog-post.hbs

<article class="blog-post">
<h1>{{title}}</h1>
<p>{{yield}}</p>
<p>Edit title: {{input type="text" value=title}}</p>
</article>
```

```app/routes/index.js
var posts = [{
title: "Rails is omakase",
body: "There are lots of à la carte software environments in this world."
}, {
title: "Broken Promises",
body: "James Coglan wrote a lengthy article about Promises in node.js."
}];

export default Ember.Route.extend({
model: function() {
return posts;
Copy link
Member

Choose a reason for hiding this comment

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

^^

Copy link
Member

Choose a reason for hiding this comment

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

Please indent this return posts two spaces.

}
});
```

```app/components/blog-post.js

Copy link
Member

Choose a reason for hiding this comment

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

Extra newline

export default Ember.Component.extend({

});
```
35 changes: 16 additions & 19 deletions source/components/passing-properties-to-a-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ template scope in which it is used.
For example, imagine you have a `blog-post` component that is used to
display a blog post:

```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>Component: {{title}}</h1>
<p>Lorem ipsum dolor sit amet.</p>
</script>
```app/templates/components/blog-post.hbs
<h1>Component: {{title}}</h1>
<p>Lorem ipsum dolor sit amet.</p>
```

You can see that it has a `{{title}}` Handlebars expression to print the
value of the `title` property inside the `<h1>`.

Now imagine we have the following template and route:

```js
App.IndexRoute = Ember.Route.extend({
```app/routes/index.js
export default Ember.Route.extend({
model: function() {
return {
title: "Rails is omakase"
Expand All @@ -26,8 +24,8 @@ App.IndexRoute = Ember.Route.extend({
});
```

```handlebars
{{! index.handlebars }}
```app/templates/index.hbs

<h1>Template: {{title}}</h1>
{{blog-post}}
```
Expand All @@ -36,7 +34,7 @@ Running this code, you will see that the first `<h1>` (from the outer
template) displays the `title` property, but the second `<h1>` (from
inside the component) is empty.

<a class="jsbin-embed" href="http://jsbin.com/japiv/1/embed?live">JS Bin</a>
<!---<a class="jsbin-embed" href="http://jsbin.com/wucabozico/1/embed?live">JS Bin</a>-->

We can fix this by making the `title` property available to the
component:
Expand All @@ -48,8 +46,8 @@ component:
This will make the `title` property in the outer template scope
available inside the component's template using the same name, `title`.

<a class="jsbin-embed" href="http://jsbin.com/japiv/2/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>
<!---<a class="jsbin-embed" href="http://jsbin.com/reyazoseru/2/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>-->

If, in the above example, the model's `title` property was instead
called `name`, we would change the component usage to:
Expand All @@ -58,8 +56,8 @@ called `name`, we would change the component usage to:
{{blog-post title=name}}
```

<a class="jsbin-embed" href="http://jsbin.com/japiv/3/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>
<!---<a class="jsbin-embed" href="http://jsbin.com/wesuvozifo/2/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>-->

In other words, you are binding a named property from the outer scope to
a named property in the component scope, with the syntax
Expand All @@ -71,9 +69,8 @@ values stay in sync. In the following example, type some text in the
text field either in the outer template or inside the component and note
how they stay in sync.


<a class="jsbin-embed" href="http://jsbin.com/fehewu/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>
<!---<a class="jsbin-embed" href="http://jsbin.com/cajarokava/1/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>-->

You can also bind properties from inside an `{{#each}}` loop. This will
create a component for each item and bind it to each model in the loop.
Expand All @@ -83,5 +80,5 @@ create a component for each item and bind it to each model in the loop.
{{blog-post title=post.title}}
{{/each}}
```
<a class="jsbin-embed" href="http://jsbin.com/yexeyi/embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>
<!---<a class="jsbin-embed" href="http://jsbin.com/kobakujejo/1//embed?live">JS Bin</a>
<script src="http://static.jsbin.com/js/embed.js"></script>-->
Loading