Permalink
Browse files

changes

  • Loading branch information...
vicramon committed May 1, 2014
1 parent e249b79 commit df72abf054a9e257f3588b9c6223ee1e16be9177
View
@@ -1,28 +1,16 @@
# Conclusion
I hope that this tutorial provided a good introduction to the Ember framework, and maybe was even fun along the way. Please don't hesitate to [let me know](mailto:vic@vicramon.com) if anything is unclear or needs more explanation.
I hope that this tutorial provided a good introduction to the Ember framework and was maybe even fun along the way. Please don't hesitate to [let me know](mailto:vic@vicramon.com) if anything is unclear or needs further explanation.
## Continuing Learning
## Where To Now?
If you want to keep learning I recommend reading through the [Ember Guides](http://emberjs.com/guides/) and the [Ember API Docs](http://emberjs.com/api/). They are very detailed and they do an excellent job explaining all the nuances of Ember.
After that, I think building your own application is the best way to learn.
## Take Home Work
A fun exercise could be to add functionality to create a new lead in the app we just built. I'll get you started. Here's how I'd do the route:
```coffee
# app/assets/javascripts/router.js.coffee
App.Router.map ->
@resource 'leads', path: '/', ->
@route 'new'
# etc...
```
Beyond that, I think building your own applications is the best way to learn.
## Extending this Tutorial
I'm considering adding more to the tutorial to help cover more Ember topics. If you'd like this then let me know. Also, if there's anything in particular that you think would be cool to add then let me know.
I'm considering adding more to the tutorial to cover more Ember topics. If you'd like this then let me know. Also, if there's anything in particular that you think would be cool to add then please tell me.
This tutorial is [on GitHub](https://github.com/vicramon/ember-tutorial-app), so you could even add a chapter yourself if you want to!
@@ -28,7 +28,7 @@ App.LeadsNewRoute = Ember.Route.extend
## Create the Template
And here's our new lead template. Note that it goes in `/templates/leads/` because it's a `route` nested under a resource named `leads`.
And here's our new lead template. Note that it goes in `templates/leads/` because it's a `route` nested under a resource named `leads`.
```
// app/assets/javascripts/templates/leads/new.js.emblem
@@ -95,11 +95,11 @@ article#leads
link-to 'leads.new' | New Lead
```
Now refresh and try it. Everything should work, but it's not perfect. As is you can create leads where every attribute is null. We should perform some validations here to prevent this.
Now refresh and try it. Everything should work, but it's not perfect. You can create leads where every attribute is null. We should perform a validation here to prevent this.
## Perform Validations
Validation libraries for Ember exist and if you want to use one I recommend [Dockyard's Ember Validations](https://github.com/dockyard/ember-validations) library. However, given Ember's robust object system and the control it gives you over the client, you don't necessarily need a library.
Validation libraries for Ember exist and if you want to use one I recommend [Dockyard's Ember Validations](https://github.com/dockyard/ember-validations) library. However, given Ember's robust object system and the large amount of control it gives you over the client, you don't necessarily need a library.
I'm going to do these validations by hand. There are any number of different ways to do validations, this is just one.
@@ -149,6 +149,8 @@ setupController: (controller) ->
controller.set 'showError', false
```
Now if you create the error, leave, then come back, the form should be fully reset. That's it for adding leads. This chapter feels a bit dry, but creating new records is probably something you'll do a lot so it's good to know.
Now if you create the error, leave, then come back, the form should be fully reset.
That's it for adding leads. This chapter feels a bit dry, but creating new records is probably something you'll do a lot so it's good to know.
The next chapter is more exciting: we're going to instantly search leads.
@@ -16,7 +16,7 @@ p
## Create the Controller Action
Template actions are handled in the controller, so open up the `LeadController` and add the `delete` action:
Template actions are handled in the controller, so open up the `LeadController` and add a `delete` action:
```coffee
# app/assets/javascripts/controllers/lead.js.coffee
@@ -1,16 +1,15 @@
# Deploying to Heroku
The world should see our masterpiece. We can deploy our app to Heroku with very little hassle.
<!-- issue: gitkeep in components? -->
The world should see our masterpiece. If you use Git and Heroku then you can deploy your app very quickly.
First add the `rails_12factor` gem that Heroku likes you to have. Bundle and commit. Then run these commands:
```shell
heroku create <whatever-name-you-want>
git push heroku master
heroku run rake db:migrate db:populate
heroku open
```
@@ -1,10 +1,8 @@
# Editing a Lead Part II
Now we're going to do the other half of editing. A user clicks on the "edit" link and sees fields to edit the lead's name, phone, and email.
Now let's finish the second half of editing. In this scenario a user clicks on the "edit" link and sees fields to edit the lead's name, phone, and email.
This UI will replace the UI that shows the lead, so we'll have to do some special work to handle that.
Here we go.
This UI need will replace the UI that shows the lead, so we'll have to do some special work to handle that.
## Add a Route
@@ -16,54 +14,53 @@ As always, add a route first. We will place an `edit` route under our existing `
@route 'edit'
```
Note that you need to add a `, ->` after the `lead` resource, otherwise you'll get an error.
Make sure to add `, ->` after the lead resource.
This route is going to look for a `LeadEdit` controller, view, and template.
## Create the Template
I'm going to add the template first because it will inform us about what actions we need to handle in the controller.
Since this `route` is nested inside a `resource`, Ember expects the template to be inside a subdirectory with the name of the resource. Thus, this template must be located in `templates/lead/`.
Since this `route` is nested inside a `resource`, Ember expects the template to be inside a subdirectory with the name of the resource. So this template will be `app/assets/javascripts/templates/lead/edit.js.emblem`.
If you're not sure where to place a template just look in the Ember Inspector's "Routes" tab to find out.
If you're not sure where to place a template just look in the Ember Inspector's "Routes" tab.
```
// app/assets/javascripts/templates/lead/edit.js.emblem
article#lead
h1
fullName
model.fullName
form
fieldset
dl
dt: label First Name:
dd: view Ember.TextField value=firstName
dd: view Ember.TextField value=model.firstName
dl
dt: label Last Name:
dd: view Ember.TextField value=lastName
dd: view Ember.TextField value=model.lastName
dl
dt: label Email:
dd: view Ember.TextField value=email
dd: view Ember.TextField value=model.email
dl
dt: label Phone:
dd: view Ember.TextField value=phone
dd: view Ember.TextField value=model.phone
fieldset.actions
input type='submit' value='Save Changes' click="saveChanges"
a.cancel click="cancel" cancel
a.cancel href="#" click="cancel" cancel
```
Ember gives you a `Ember.TextField` view which renders a text input. Just assign `value` to the property you want to bind to.
You can use a colon `:` in Emblem to nest elements on the same line.
Notice that I'm using `firstName` and `lastName` instead of `model.firstName` and `model.lastName`. Using `model` would work just fine, but it's unnecessary. The template always looks to the controller for a property, and if it's not in the controller then it will look to the model. You may want to use `model` for clarity, but it's up to you.
Ember gives you the `Ember.TextField` view which renders a text input. Just assign `value` to the property you want to bind to.
The `form` tag actually doesn't do anything, it's just there for markup.
The `form` tag doesn't actually do anything, it's just there for markup.
This template has two actions: `saveChanges` and `cancel`. Let's implement them now.
@@ -93,15 +90,17 @@ We need a way to get to our new route. Add a link inside the `h1` tag in the `le
```coffee
# app/assets/javascripts/templates/lead.js.coffee
h1
fullName
model.fullName
link-to 'edit' 'lead.edit' model classNames='edit'
```
The first argument, `'edit'`, is the link text. The second, `'lead.edit'`, is the route name.
## Try It
Open the browser and try clicking the edit link. You should see the URL change, but nothing else should happen. Can you figure out why?
**Outlets**, don't forget about them. If a template doesn't appear, always ask yourself: **did I add an outlet?!** If you're like me, you'll forget one at some point and be flaggergasted at why your template isn't showing up.
**Outlets**, don't forget about them. If a template doesn't appear, always ask yourself: **did I add an outlet?!** If you're like me, you'll forget one at some point and be super annoyed that your template isn't showing up.
Our `edit` route is nested under `lead` so Ember is trying to render the template into an `outlet` tag inside the `lead` template. Since it can't find it, nothing happens.
@@ -111,6 +110,7 @@ Add an outlet to the top of the `lead` template:
// app/assets/javascripts/templates/lead.js.emblem
outlet
```
Now try it. It should work, but now we have a new problem: the show UI for a lead is still be present. That's because **nested routes means nested UI**. Since the `lead` resource is still active, the UI is still active.
There's a simple fix to this -- we'll just hide the show UI when we're editing.
@@ -133,7 +133,7 @@ unless isEditing
// etc...
```
Now whenever we visit the edit route we need to set `isEditing` to true. We can do that inside the `LeadEdit` route, because... routes handle setup and teardown! We haven't made one yet, so do it now:
Now whenever we visit the edit route we need to set `isEditing` to true. We can do that inside the `LeadEdit` route. We haven't made one yet, so do it now:
```coffee
# app/assets/javascripts/routes/lead_edit.js.coffee
@@ -145,7 +145,7 @@ App.LeadEditRoute = Ember.Route.extend
Now we see those route hooks coming in handy! On `activate` we get the `LeadController` and set `isEditing` to true. On `deactivate` we do the opposite. And boom, we're done.
We could do one last thing for clarity: we could add `isEditing` to the `LeadController` and default it to false.
We could do one last thing for clarity -- add `isEditing` to the `LeadController` and default it to false.
```coffee
# app/assets/javascripts/controllers/lead.js.coffee
@@ -156,6 +156,6 @@ App.LeadController = Ember.ObjectController.extend
#etc...
```
This way future programmers will know that we have an `isEditing` property and it should be `false` by default. We don't have to do this but I think it's good style.
This way future programmers (or our future selves) will know that we have an `isEditing` property on this controller and it should be `false` by default. We don't have to do this but I think it's good style.
Now that we can edit everything about a lead I'll show you how to delete them.
Now that we can edit everything about leads I'll show you how to delete them.
@@ -2,17 +2,20 @@
Let's create a search box that will instantly search leads by name as we type.
The neat thing about this, as you'll see, is that it can be accomplished in a very clean manner with a surprisingly small amount of code. That, my friend, is the beauty of Ember.
The neat thing about this is that it can be accomplished with a surprisingly small amount of code in a very clean manner. That, my friend, is the beauty of Ember.
## Add the Search Field
This will go at the top of the list of leads, right under the `h1`:
Add a text field view at the top of the list of leads, right under the `h1`:
```
# app/assets/javascripts/templates/leads.js.emblem
article#leads
h1 Leads
h1
| Leads
link-to 'leads.new' | New Lead
view Ember.TextField value=search placeholder="search" classNames="search"
ul
# etc ...
```
@@ -49,12 +52,12 @@ The `leads` property looks to see if there is a search string. If there is, it r
`searchedLeads` gets the search string and lower cases it. It then runs `filter` on `@`, which is the list of leads, and returns the leads where the full name includes the search string.
`searchedLeads` needs to watch `@each.fullName', which means that the property will be updated whenever the full name of any lead changes.
`searchedLeads` needs to depend on `@each.fullName', which means that the property will be updated whenever the full name of any lead changes.
## Try It
It should work right now. There are two cool things to notice here.
First, as you search the list of names stays sorted by first and last name. That's `sortProperties` in action.
First, as you search the list of names they stay sorted by first and last name. That's `sortProperties` in action.
Second, try clicking on a lead, then entering a search string that doesn't match. Then, edit the lead's name to something that matches and watch it appear in the search list. That's pretty cool, and it's a good example of how everything is properly bound together.
@@ -41,15 +41,15 @@ article#lead
p
' Name:
= model.fullName
model.fullName
p
' Email:
= model.email
model.email
p
' Phone:
= model.phone
model.phone
```
The single quote `'` leaves a trailing whitespace after the line.
@@ -111,6 +111,9 @@ header article .logo a {
font-weight: 500;
color: white;
}
header article .logo a:hover {
text-decoration: none;
}
header article nav {
padding: 15px 0 0 0;
float: right;

0 comments on commit df72abf

Please sign in to comment.