Download - CodeSchool-Emberjs
![Page 1: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/1.jpg)
Setting up Ember.js
Level 1 - Warming Up
![Page 2: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/2.jpg)
Ember.js“A framework for creating ambitious web applications”
![Page 3: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/3.jpg)
Need To KnowJavaScriptHTML & CSS jQuery
Ruby & Rails Python & Django
Don’t need to know
![Page 4: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/4.jpg)
Why Ember.js
![Page 5: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/5.jpg)
Why Ember.js?
HTML
Web App
iOS Android
API
Database
Ember.js
![Page 6: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/6.jpg)
Why Ember.jsYou want your application to feel responsive
![Page 7: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/7.jpg)
When Not to Use
• Blog
• Newspaper
• Static Content
When your web app doesn’t have a lot of interactivity.
![Page 8: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/8.jpg)
Getting Started With Ember.js
http://emberjs.com/
1. Grab the starter kit & Ember Data
https://github.com/emberjs/data
http://getbootstrap.com/
2. We’re using Twitter Bootstrap
![Page 9: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/9.jpg)
Setting Up index.htmlindex.html<html> <head> <script src="jquery.js"></script> <script src="handlebars.js"></script> <script src="ember.js"></script> <script src="ember-data.js"></script> <script src="app.js"></script> ! <link href="bootstrap.css" media="screen" rel="stylesheet" /> </head> </html>
![Page 10: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/10.jpg)
Test Drive
![Page 11: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/11.jpg)
The Ember Application
app.js
var App = Ember.Application.create({ });
We’re namespacing our application App, but you could name this variable anything
We need a single object to contain all functionality of our app.
![Page 12: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/12.jpg)
Ember Application
When you see this icon, it’s our application
The roots of our application Need to create an application only once Everything we do comes after
![Page 13: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/13.jpg)
Ember Application Options
var App = Ember.Application.create({ LOG_TRANSITIONS: true });
Not required, but helpful for debugging!
Inside our application we can send in a JavaScript Object with options.
For example, if we wanted to log out a message to the browser every time a new page is accessed.
![Page 14: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/14.jpg)
The HTML Contentapp.js
var App = Ember.Application.create({ LOG_TRANSITIONS: true });
<html> ... <body> <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer> </body> </html>
index.html
![Page 15: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/15.jpg)
Running Our First AppIf we open the app and view the source you’ll notice Ember added a body class and data-ember-extension to our code.
<!DOCTYPE html> <html> <head>...</head> <body class='ember-application' data-ember-extension='1'> <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer> </body> </html>
So Ember will know the part of the page it will control.
![Page 16: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/16.jpg)
We Need to Dynamically Update
We want to move everything inside <body> into a template
We’re going to want to dynamically update the content inside this body. Thus, we need a templating language.
body
div.navbar
div.container
footer.container
<div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer>
<body>
</body>
![Page 17: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/17.jpg)
div.navbar
div.container
footer.container
bodytemplate
Handlebars Template
This is a Handlebars template
Handlebars templates look like regular HTML with handlebars expressions
<body><script type='text/x-handlebars'>
<div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer> </script></body>
![Page 18: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/18.jpg)
Running With HandlebarsEmber by default will render the Handlebars template into a div.
<!DOCTYPE html> <html> <head>...</head> <body class='ember-application' data-ember-extension='1'> <div id='ember248' class='ember-view'> <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer> </div> </body> </html>
So Ember can uniquely identify this div
![Page 19: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/19.jpg)
Ember Template
Works just like HTML Ember uses the Handlebars.js for templates The part of our application people see
When you see this icon, it’s an Ember template
![Page 20: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/20.jpg)
Named Templates
Level 1 - Warming Up
![Page 21: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/21.jpg)
Reviewindex.html
We can put HTML inside a Handlebars template
What if we wanted to make the content in this template dynamic?
<body> <script type='text/x-handlebars'>
</script></body>
<div class='navbar'>...</div>
<footer class='container'>...</footer> <div class='container'> </div>...
![Page 22: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/22.jpg)
Adding Data to Templatesindex.html<script type=‘text/handlebars’ data-template-name=‘application’> <div>...</div></script>
Called a “handlebars expression”
{{siteName}}’s value will need to be provided by our Ember app, so it can print The Flint & Flame!
Later on in this course we’ll be using templates to add dynamic content.
<script type='text/x-handlebars'> <div class='navbar'>...</div> <div class='container'>
<footer class='container'>...</footer>
<h1>Welcome to {{siteName}}!</h1> </div>
</script>
![Page 23: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/23.jpg)
Our Current Webpage Layout
div.navbar
div.container
footer.container
bodytemplate
We are going to have multiple pages on our website.
• Homepage
• About Page
• Product List
![Page 24: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/24.jpg)
div.navbar
div.container
footer.container
bodytemplate
<h1>About The Fire Spirits</h1>
<h1>Welcome to The Flint & Flame!</h1>
The Different Pages
About Page
Home Page
We want this to be the default
![Page 25: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/25.jpg)
div.navbar
div.container
footer.container
body
<h1>About The Fire Spirits</h1>
<h1>Welcome to The Flint & Flame!</h1>
We Need to Name our Templates
We want this to be the default
‘application’ template‘about’ template
‘index’ template
![Page 26: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/26.jpg)
Adding the Template Name
index.html
<script type=‘text/handlebars’ data-template-name=‘application’> <div>...</div></script>
The application template is shown for every page by default.
Each template needs a unique name.
<script type='text/x-handlebars' <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer></script>
data-template-name='application'>
![Page 27: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/27.jpg)
Adding the Homepage Templateindex.html
‘index’ is what we’ll call the homepage template name
<script type='text/x-handlebars' <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer></script>
data-template-name='application'>
<script type='text/x-handlebars' data-template-name='index'> <h1>Welcome to The Flint & Flame!</h1> </script>
![Page 28: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/28.jpg)
Adding our About Templateindex.html
<script type='text/x-handlebars' <div class='navbar'>...</div> <div class='container'>...</div> <footer class='container'>...</footer></script>
data-template-name='application'>
<script type='text/x-handlebars' data-template-name='index'> <h1>Welcome to The Flint & Flame!</h1> </script>
<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
![Page 29: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/29.jpg)
Only our application template is showing!
No welcome message!
![Page 30: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/30.jpg)
But where do they go?We need a way of telling our templates where on the page to render.
?<script type='text/x-handlebars' data-template-name='application'> <div class='navbar'>...</div><div class='container'> </div>
<footer class='container'>...</footer> </script> !<script type='text/x-handlebars' data-template-name='index'> <h1>Welcome to The Flint & Flame!</h1> </script> !<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
...
![Page 31: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/31.jpg)
OutletUsing the handlebars expression “outlet” we’re giving our code a hint as to where templates should be inserted.
If our Ember code reaches an {{outlet}}, by default it will look to find a template named ‘index’ and render that in place of the outlet.
<script type='text/x-handlebars' data-template-name='application'> <div class='navbar'>...</div><div class='container'>{{outlet}}</div>
<footer class='container'>...</footer> </script> !<script type='text/x-handlebars' data-template-name='index'> <h1>Welcome to The Flint & Flame!</h1> </script> !<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
![Page 32: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/32.jpg)
Our index template is rendered within our application template
![Page 33: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/33.jpg)
The Router
Level 1 - Warming Up
![Page 34: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/34.jpg)
Routing Our Way Inindex.html<script type='text/x-handlebars' data-template-name='application'> <div class='navbar'>...</div> <div class='container'> {{outlet}} </div> <footer class='container'>...</footer> </script> !<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
How can we ever render the ‘about’ template?and map it to a URL, like http://example.com/about ?
![Page 35: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/35.jpg)
The Ember Router
Translates a path into a route. Like a tree trunk — all requests start here.
This is our Router icon
![Page 36: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/36.jpg)
Routing Our Way In
Browser Request
Figures out the route name for each request
Ember Router
?
??
??
?
Handlebars Template
![Page 37: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/37.jpg)
Introducing the Routerapp.js
Every page for our website will be defined by the router.
var App = Ember.Application.create({ LOG_TRANSITIONS: true });
App.Router.map(function() {
});…
![Page 38: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/38.jpg)
How can we render the ‘about’ template?
App.Router.map(function() {
});…
app.js
<script type='text/x-handlebars' data-template-name='application'> … {{outlet}} … </script> !<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
index.html
![Page 39: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/39.jpg)
The about Route
App.Router.map(function() {
});
app.js
this.route('about');
http://example.com#/about
/about
When an outlet is found, ‘about’ template is loaded into it.
about
URL
Path
Route
<script type='text/x-handlebars' data-template-name='application'> … {{outlet}} … </script> !<script type='text/x-handlebars' data-template-name='about'> <h1>About The Fire Spirits</h1> </script>
![Page 40: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/40.jpg)
Template Naming
![Page 41: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/41.jpg)
What’s with the Hash Sign?
http://example.com#/about http://example.com/about
There is no ‘about/index.html’ or ‘about’ file path our application knows about
![Page 42: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/42.jpg)
Where our Application ExistsIn Ember.js, our entire application is loaded through one file.
• Homepage • About Page • Product List
In our case index.html which is loaded from http://example.com
No matter what page we load…
…we will have first called up index.html
This loads up all our templates!
![Page 43: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/43.jpg)
All Templates Sent!In Ember.js, all our templates are sent over when the application loads.
Everything Sent
application
index
about
product list
Server Client Browser
application
index
about
product list
Initial Requestapplication
about
![Page 44: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/44.jpg)
What does the hash say?http://example.com#/about
When a browser see’s this it knows the file path information is over
Loads ‘’ or root file path
http://example.com/about Loads ‘about’ file path
http://example.com/store#/shopping_cart Loads ‘store’ file path
![Page 45: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/45.jpg)
Back to Our About Route
App.Router.map(function() {
});
app.js http://example.com#/about
/about
about
URL
Ember Path
Route
What if we want the ‘/aboutus’ path to use the about route?
this.route('about'); File Path <none>
![Page 46: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/46.jpg)
Using ‘/aboutus’ custom path
App.Router.map(function() {
});
app.js
http://example.com#/aboutus
/aboutus
about
this.route('about' );, { path: '/aboutus' }
URL
Ember Path
Route
![Page 47: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/47.jpg)
What about the Index Route?
App.Router.map(function() {
});
app.js
http://example.com
index
this.route('about' );, { path: '/aboutus' }
<none>
this.route('index', { path: '' });
?
?
URL
Ember Path
Route
![Page 48: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/48.jpg)
No! This is a Default
App.Router.map(function() {
});
app.js
this.route('about' );, { path: '/aboutus' }
this.route('index', { path: '' });
Default Behavior!
http://example.com
index
<none>
URL
Ember Path
Route
![Page 49: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/49.jpg)
![Page 50: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/50.jpg)
Handlebars
Level 2 - Rendering the Flame
![Page 51: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/51.jpg)
Review
App.Router.map(function() { this.route('about'); });
app.js
Router is solely responsible for all URLs.
How do we link to the about and index route?
![Page 52: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/52.jpg)
Linking to Routes
index.html
App.Router.map(function() { this.route('about'); });
<a href="#/about">About</a>
app.js
Router is solely responsible for all URLs.
It’s considered a bad practice to do this. We don’t hard code URL paths. Instead we ask the routes for their path.
<a href="#/">Home</a>
![Page 53: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/53.jpg)
The Handlebars link-to helperUse the route name to look up the path.
{{#link-to 'about'}}About{{/link-to}}
<a class="ember-view" href="#/" id='ember2'>Homepage</a><a class="ember-view" href="#/about" id='ember3'>About</a>
link-to will determine the path based on the route name.
{{#link-to 'index'}}Homepage{{/link-to}}
![Page 54: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/54.jpg)
Extra AttributesHow to add a custom class to our link.
<a class="ember-view navbar-brand" href="#/" id='ember2'>Homepage</a>
Rendered from template into
{{#link-to 'index' }}Homepage{{/link-to}} class='navbar-brand'
![Page 55: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/55.jpg)
![Page 56: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/56.jpg)
![Page 57: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/57.jpg)
tagName option
index.html{{#link-to 'index' tagName='li'}}Home{{/link-to}} {{#link-to 'about' tagName='li'}}About{{/link-to}}
Notice the href disappeared!
<li class='ember-view' id='ember1'>Home</li> <li class='ember-view' id='ember2'>About</li>
How to change the HTML element.
It will still work, because Ember adds click handlers.
![Page 58: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/58.jpg)
TitleBody Level One
Demo showing li links still working
![Page 59: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/59.jpg)
Controller Basics
Level 2 - Rendering the Flame
![Page 60: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/60.jpg)
Review
index.html
{{#link-to 'about' tagName='li'}}About{{/link-to}}
App.Router.map(function() { this.route('about'); });
app.js
Mapped paths to route names.
Link to other pages using route names, not paths.
![Page 61: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/61.jpg)
Template Variables
index.htmlYou can use properties in your template
<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p> </script>
How do you set a property for use in a template?
![Page 62: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/62.jpg)
Ember Controller
Where a template looks to find a property value
Decorate your applications data for the template
Contains information that is not saved to a server
Each Ember Controller will use this icon
![Page 63: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/63.jpg)
Routing Our Way InBrowser Request
Router
?
??
?? Handlebars Template
ControllerProvides properties for the template
![Page 64: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/64.jpg)
Asking the Controller
app.jslooks for a controller named “IndexController”, and the property inside it.
index.html<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p> </script>
There are 6 products
App.IndexController = Ember.Controller.extend({
});productsCount: 6
![Page 65: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/65.jpg)
Every Route has a Default Controller
If we want to declare properties that get rendered inside a template, then we can declare this Controller.
App.Router.map(function() { this.route('about'); });
App.AboutController = Ember.Controller.extend({ });
Behind the scenes, Ember creates this About controller.
![Page 66: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/66.jpg)
Binding with Metamorph!index.html
<p>There are <script id="metamorph-2-start" type="text/x-placeholder"></script> 6 <script id="metamorph-2-end" type="text/x-placeholder"></script> products </p>
Ember needs to wrap properties so it can potentially update it later. (AKA. Binding)
<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p></script>
![Page 67: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/67.jpg)
Binding Attributes?
index.html
app.js
App.IndexController = Ember.Controller.extend({ productsCount: 6,logo: '/images/logo.png'
});
<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p>
</script> <img src='{{logo}}' alt='Logo' />
![Page 68: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/68.jpg)
![Page 69: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/69.jpg)
Property Bindingindex.html
<img src=" <script id="metamorph-2-start" type="text/x-placeholder"></script> /images/logo.png <script id="metamorph-2-end" type="text/x-placeholder"></script> >
We need to bind attributes differently.
<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p> <img src='{{logo}}' alt='Logo' /></script>
![Page 70: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/70.jpg)
How to Bind Attributesindex.html
<img src="/images/logo.png" data-bindattr-1="1">
Ember meta data is still added to enable binding
<script type='text/x-handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p>
</script> <img {{bind-attr src='logo'}} alt='Logo' />
![Page 71: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/71.jpg)
![Page 72: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/72.jpg)
Dynamic Contentindex.html<script type='text/x-handlebars' data-template-name='index'> <p>Rendered on {{time}}</p> </script>
How do we fetch the current time?
(new Date()).toDateString()
We need to create a property that calls this function:
This is more then just a value, we need to execute some code to get the value.
![Page 73: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/73.jpg)
Controller Functions
app.jsindex.html<script type='text/x-handlebars' data-template-name='index'> <p>Rendered on {{time}}</p> </script>
app.js
We need to tell Ember this is a property and to call it
(new Date()).toDateString()
App.IndexController = Ember.Controller.extend({ productsCount: 6, logo: '/images/logo.png', time: function() {
return
}
}});
![Page 74: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/74.jpg)
Controller Functions as Properties
app.js<script type='text/x-handlebars' data-template-name='index'> <p>Rendered on {{time}}</p> </script>
time will be called, and that value used as a property
index.html
app.js
(new Date()).toDateString()
App.IndexController = Ember.Controller.extend({ productsCount: 6, logo: '/images/logo.png', time: function() {
return}
});.property()
![Page 75: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/75.jpg)
TitleScreenshot with the time showing
![Page 76: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/76.jpg)
Resource Routes
Level 3 - A Route Through the Woods
![Page 77: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/77.jpg)
Reviewapp.js
The name of the controller matches the route and template names
index.html
Templates can use properties from a controller
App.IndexController = Ember.Controller.extend({ productsCount: 6, logo: '/images/test.png', time: function() { return (new Date()).toDateString(); }.property() });
<script type='text/handlebars' data-template-name='index'> <p>There are {{productsCount}} products</p> <img {{bind-attr src='logo'}} alt='Logo' /> <p>Current Time: {{time}}</p> </script>
![Page 78: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/78.jpg)
We’ll show all of our products on a new products page
![Page 79: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/79.jpg)
Use route for adjectives, verbs, adverbsapp.js
this.route('signup'); this.route('ignite'); this.route('help'); this.route('rate');
this.route('onsale'); this.route('expiring'); this.route('new'); this.route('internal');
Adjective Routes Verb Routes
App.Router.map(function() { this.route('about');});
![Page 80: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/80.jpg)
Use ‘Resource’ Routes for Nounsapp.js
this.resource('tree'); this.resource('review'); this.resource('books'); this.resource('contacts');
Noun Resources
Can be singular or plural
The resource keyword has some additional functionality.That difference is what this level is all about!
App.Router.map(function() { this.route('about');
}); this.resource('products');
![Page 81: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/81.jpg)
Resource Route Options
app.js
Like with route, we can pass in an optional path
App.Router.map(function() { this.route('about');
});, { path: '/items' } this.resource('products' );
![Page 82: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/82.jpg)
Resource Viewsapp.js
index.htmlMatches the route name
<script type='text/x-handlebars' data-template-name='products'> <h1>Products</h1> </script>
App.Router.map(function() { this.route('about');
}); this.resource('products');
![Page 83: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/83.jpg)
Linking to Resources
index.html
<script type='text/x-handlebars' data-template-name='application'> ... {{#link-to 'products' tagName='li'}}Products{{/link-to}} ... </script>
We can link to this route with its name like any other.
![Page 84: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/84.jpg)
How can we add some data to this page?
The link has a class of active if we’re within the products routeRendering the products template
http://example.com#/products
![Page 85: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/85.jpg)
Ember Route
Fetches data and passes it to the Ember Controller
Decides on what model to use for the current route
Decides which template to render to the screen
Each Ember Route will use this iconA model could be a JavaScript Object or an Array of objects
![Page 86: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/86.jpg)
Ember RouteProvides data for the controller
Ember RouterTranslates a path into a route
Don’t get these confused
![Page 87: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/87.jpg)
Ember RouteBrowser Request
Router
??
?? Handlebars Template
Controller
Route
Provides data for the controller
![Page 88: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/88.jpg)
Router? Route? Controller?
created by Ember if not defined
Decorates the model, provides property values
App.ProductsController = Ember.Controller.extend({ });
this.resource('products');
Used to define routes our application accepts.
Responsible for getting data from external resources
created by Ember if not defined
Router
Route
Controller
App.ProductsRoute = Ember.Route.extend({ });
![Page 89: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/89.jpg)
A Very Basic Modelapp.js
App.PRODUCTS = [ { title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png' }, { title: 'Kindling', price: 249, description: 'Easily…', isOnSale: false, image: 'kindling.png' } ];
app.js
This could be pulled from an API
The model property should return an an object or an array.
App.ProductsRoute = Ember.Route.extend({model: function() { return App.PRODUCTS; }
});
![Page 90: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/90.jpg)
Putting it All Together
Model
The Route is responsible for fetching the model. Ember will set this model on the Controller, and that’s what’ll be used in your Handlebars Template.
index.html
Router
Route
Controller
Template
<script type='text/x-handlebars' data-template-name='products'> <h2>Products</h2> {{model}}</script>
![Page 91: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/91.jpg)
Rendering the Modelindex.html
<h2>Products</h2> [object Object],[object Object]
Model is an array, so we’ll need to loop over it!
<script type='text/x-handlebars' data-template-name='products'> <h2>Products</h2> {{model}}</script>
![Page 92: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/92.jpg)
Looping Over the Array of Objectsindex.html
<h1>Products</h1> <h2>Flint</h2> <h2>Kindling</h2>
<script type='text/x-handlebars' data-template-name='products'>
</script>
<h2>Products</h2>{{#each product in model}}
<h2>{{product.title}}</h2>{{/each}}
![Page 93: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/93.jpg)
A Simpler #each Loop
index.html
Within the #each loop, you can access properties on that product
#each without extra options will look for a model property.
<script type='text/x-handlebars' data-template-name='products'> ...
</script>
{{#each}}<h2>{{title}}</h2>
{{/each}}
![Page 94: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/94.jpg)
A Dash of Styleindex.html
Output a few more properties and add some styling
<script type='text/x-handlebars' data-template-name='products'><h1>Products</h1><ul class='list-unstyled col-md-8'> {{#each}} <li class='row'> <img {{bind-attr src='image'}} class='img-thumbnail col-md-5'/> <div class='col-md-7'> <h2>{{title}}</h2> <p class='product-description'>{{description}}</p> <p><button class='btn btn-success'>Buy for ${{price}}</button></p> </div> </li> {{/each}} </ul></script>
![Page 95: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/95.jpg)
![Page 96: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/96.jpg)
Related and Dynamic Routes
Level 3 - A Route Through the Woods
![Page 97: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/97.jpg)
Review
app.jsAdded a resource route
Create a Route to provide the model
How would we create a page for a specific product? Based on title?
{ title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png' }
App.ProductsRoute = Ember.Route.extend({ model: function() { return App.PRODUCTS; } });
});
App.Router.map(function() { this.route('about'); this.resource('products');
![Page 98: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/98.jpg)
Adding a Singular Routeapp.js
Nothing unique to a specific product in path
We need a path with a parameter. Maybe #/products/<product_title>
App.Router.map(function() { this.route('about'); this.resource('products');
});this.resource('product');
![Page 99: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/99.jpg)
Dynamic Segment Routesapp.js
Our route object can use the title
{ title: 'Flint' }
{ title: '4' }
http://example.org#/products/Flint
http://example.org#/products/4
App.Router.map(function() { this.route('about'); this.resource('products');
});, { path: '/products/:title' }this.resource('product' );
![Page 100: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/100.jpg)
Logging out Params from the Routeapp.js
{ title: 'Flint' }http://example.org#/products/Flint
App.Router.map(function() { this.route('about'); this.resource('products');
});
App.ProductRoute = Ember.Route.extend({ model: function(params) { ! } });
console.log(params);
, { path: '/products/:title' }this.resource('product' );
![Page 101: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/101.jpg)
Returning a Single Object
app.js
We need to lookup a PRODUCT with title of params.title
App.PRODUCTS = [
, { title: 'Kindling', price: 249, description: 'Easily…', isOnSale: false, image: 'kindling.png' } ];
App.ProductRoute = Ember.Route.extend({ model: function(params) { ! } });
{ title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png' }
![Page 102: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/102.jpg)
{ title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png' }
findBy Array HelperEmber adds helpers to JavaScript base objects, in this case to Array.
http://example.org#/products/Flint
return App.PRODUCTS.findBy('title', params.title);
App.ProductRoute = Ember.Route.extend({ model: function(params) { ! } });
![Page 103: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/103.jpg)
{ title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png' }
Our Product Templateindex.html<script type='text/x-handlebars' data-template-name='product'> <h2>{{title}}</h2> <p>{{description}}</p> <p>Buy for ${{price}}</p> </script>
First looks in the controller for properties
Second looks in the model for properties
Model
Controller
![Page 104: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/104.jpg)
Flint in the path is a dynamic segment
Our product template is rendered
![Page 105: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/105.jpg)
Styling Our Productindex.html
Our more detailed view of a product
<script type='text/x-handlebars' data-template-name='product'> <div class='row'> <div class='col-md-7'> <h2>{{title}}</h2> <h3 class='text-success'>${{price}}</h3> <p class='text-muted'>{{description}}</p> </div>
<div class='col-md-5'> <img {{bind-attr src='image'}} class='img-thumbnail img-rounded'/> </div>
</div> </script>
![Page 106: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/106.jpg)
Linking To a Productindex.html<script type='text/x-handlebars' data-template-name='products'> {{each}} {{#link-to 'product' this classNames='list-group-item'}} {{title}} {{/link-to}} {{/each}} </script> Pass in the product we want to link to
/products/Flint{{#link-to 'product' this}}
The link-to helper knows to use the this.title value in the URL since we defined our route with :title in the Router.
this.resource(‘product', { path: '/products/:title' });
Thus….
![Page 107: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/107.jpg)
![Page 108: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/108.jpg)
Nested Routes
Level 3 - A Route Through the Woods
![Page 109: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/109.jpg)
Reviewapp.js
App.Router.map(function() { this.route('about'); this.resource('products'); this.resource('product', { path: '/products/:title' }); }); !App.ProductRoute = Ember.Route.extend({ model: function(params) { return App.PRODUCTS.findBy('title', params.title); } });
Resource route with a dynamic segment
Provide the singular product for the product route
![Page 110: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/110.jpg)
Show screenshot or products page
Show screenshot or product page
We replaced the entire {{outlet}} !in our application with this content
products template rendering within {{outlet}} in the application template
![Page 111: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/111.jpg)
product template also rendering within {{outlet}} in the application template
![Page 112: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/112.jpg)
Our Existing Templates
products template
product template
A list of products
Information on a specific product
application template
div.container{{outlet}}
They both are rendered in the same {{outlet}}, but what if we wanted to do something different?
![Page 113: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/113.jpg)
Body Level One
Since we don’t have many products, it !makes since to user a master-detail view
Screencast of finished product with products staying on the side
![Page 114: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/114.jpg)
Template in a Template
application template
div.container{{outlet}}
products template
product template
How do we nest the product template inside the products template?
![Page 115: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/115.jpg)
App.Router.map(function() { this.route('about'); this.resource('products', function() { this.resource('product', { path: '/:title' }); });});
If your Views are nested your Routes should be nestedapp.js
Notice we don’t need /products anymore.
App.Router.map(function() { this.route('about'); this.resource('products'); this.resource('product', { path: '/products/:title' }); });
Nest the resources
Old Router
![Page 116: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/116.jpg)
http://example.com#/products/Flint
Following the Path
products/:titleEmber Path
Route product
URL
App.Router.map(function() { this.route('about'); this.resource('products', function() { this.resource('product', { path: '/:title' }); });});
![Page 117: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/117.jpg)
Adding an Outlet
application template
div.container{{outlet}}
products template
product template
{{outlet}}
We need an outlet to show where the product template will be rendered inside the products template.
![Page 118: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/118.jpg)
Adding the Outlet to our Templateindex.html
<script type='text/x-handlebars' data-template-name='products'> <div class='row'> <div class='col-sm-3'> <div class='list-group'> {{#each}} {{#link-to 'product' this classNames='list-group-item'}} {{title}} {{/link-to}} {{/each}} </div> </div><div class='col-sm-9'> {{outlet}} </div>
</div> </script>
![Page 119: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/119.jpg)
TitleBody Level One
/products page works
Clicking on a product works!
![Page 120: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/120.jpg)
https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi
Ember Inspector For Chrome
![Page 121: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/121.jpg)
![Page 122: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/122.jpg)
The products/index template will be shown within the products template with no product.
![Page 123: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/123.jpg)
Template for products/index Route
index.html<script type='text/x-handlebars' data-template-name='products/index'> <p class='text-muted'>Choose a product from those on the left!</p> </script>
Will be filled into the {{outlet}} of the products template
![Page 124: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/124.jpg)
![Page 125: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/125.jpg)
Level 4 - Acorn Models and Pinecone Data
Models and Ember Data
![Page 126: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/126.jpg)
app.js
ReviewWhat if we wanted to fetch products from a server?
App.PRODUCTS = [...]; !App.ProductsRoute = Ember.Route.extend({ model: function() { return App.PRODUCTS; } }); !App.ProductRouter = Ember.Route.extend({ model: function(params) { return App.PRODUCTS.findBy('title', params.title); } });
![Page 127: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/127.jpg)
Ember ModelA class that defines the properties and behavior of the data that you present to the user.
Previously our route set the model to an Array.
This is our Model icon
Every Route can have a Model.
![Page 128: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/128.jpg)
Ember ModelBrowser Request
Router
?
?? Handlebars Template
Controller
Route
Model
A class that defines the properties and behavior of the data that you present to the user.
![Page 129: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/129.jpg)
Creating an Ember Model
app.js
Next, our Ember Model needs to know what attributes it contains.
We are working with products, so lets define a product class.Models are typically nouns.
App.Product = DS.Model.extend({ });
![Page 130: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/130.jpg)
Ember Model Attributesapp.js
string
number
boolean
date
Remember our data?
We need to know what data types our Model should expect.
App.Product = DS.Model.extend({ });title: 'Flint',
price: 99, description: 'Flint is…'
,
isOnSale: true, image: 'flint.png'
{
}
,
![Page 131: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/131.jpg)
Building the Product Model
app.js
We’ll define all the different properties in our model class.
App.Product = DS.Model.extend({ title: DS.attr('string'), price: DS.attr('number'), description: DS.attr('string'), isOnSale: DS.attr('boolean'), image: DS.attr('string') });
title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png'
{
}
![Page 132: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/132.jpg)
Implied Data Types
app.js
If property types aren’t supplied, they will be implied.
App.Product = DS.Model.extend({
});
title: DS.attr(), price: DS.attr(), description: DS.attr(), isOnSale: DS.attr(), image: DS.attr()
title: , price: 99, description: , isOnSale: true,
{
}
'Acorn'
'These...'
isSeasonal: true
![Page 133: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/133.jpg)
Ember DataEmber Data makes it easy to use a Model to retrieve records from a server, cache them for performance, save updates back to the server, and create new records on the client.
This is our Ember Data icon
![Page 134: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/134.jpg)
Ember DataBrowser Request
Router
?
?Handlebars Template
Controller
Route
Model
Ember Data
![Page 135: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/135.jpg)
Ember Data Adapters
App.ApplicationAdapter = DS.RESTAdapter.extend();
This is the default adapter.
Allows us to hardcode our data in fixtures for getting started.
App.ApplicationAdapter = DS.FixtureAdapter.extend();
To communicate with an HTTP server using JSON
To load records from memory
![Page 136: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/136.jpg)
Migrating to Fixturesapp.js
We’ll need to convert this to use Ember Data FixtureAdapter.
App.PRODUCTS = [{
title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png'
},{
title: 'Kindling', price: 249, description: 'Easily…', isOnSale: false, image: 'kindling.png' } ];
![Page 137: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/137.jpg)
Ember Data Fixtures for Productapp.js
Needs to use the FIXTURES constant within the model
Need to give each product a unique ID
App. = [{
title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png'
},{
title: 'Kindling', price: 249, description: 'Easily…', isOnSale: false, image: 'kindling.png' } ];
Product.FIXTURESid: 1,
id: 2,
![Page 138: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/138.jpg)
Ember Data Has A StoreCentral repository for records in your application, available in routes and controllers.
Think of it as a cache storage of all your records.
Store
We’ll use the store to retrieve records and create new ones.
App.Product.FIXTURES
![Page 139: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/139.jpg)
Changing :title to :product_idapp.js
this.resource('products', function() { this.resource('product', { path: '/:product_id' }); });
Switch to using product_id as the dynamic segment
this.resource('products', function() { this.resource('product', { path: '/:title' }); });
Ember Data (by default) must use a unique identifier. We’ll use :product_id.
![Page 140: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/140.jpg)
Need to Update Our Routesapp.js
In order to get our fixture data out of the store
Finds all products from the fixture adapter
App.ProductsRoute = Ember.Route.extend({model: function() {
return App.PRODUCTS; } });
App.ProductsRoute = Ember.Route.extend({model: function() {
return this.store.findAll('product'); } });
![Page 141: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/141.jpg)
App.ProductRoute = Ember.Route.extend({ model: function(params) { return this.store.find('product', params.product_id); } });
Updating the Product Routeapp.js
Finds only the product with the matching ID
App.ProductRoute = Ember.Route.extend({ model: function(params) { return App.PRODUCTS.findBy(‘title', params.title); } });
![Page 142: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/142.jpg)
App.ProductRoute = Ember.Route.extend({ model: function(params) { return this.store.find('product', params.product_id); } });
Using the Default Product Route
We can delete the ProductRoute and use the default!
![Page 143: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/143.jpg)
Show new products page linking to product page
![Page 144: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/144.jpg)
Level 4 - Acorn Models and Pinecone Data
Related models
![Page 145: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/145.jpg)
Reviewapp.js
What if our products had reviews?
App.ProductsRoute = Ember.Route.extend({ model: function() { return this.store.findAll('product'); } });
App.Product = DS.Model.extend({ title: DS.attr('string'), price: DS.attr('number'), description: DS.attr('string'), isOnSale: DS.attr('boolean'), image: DS.attr('string')});
![Page 146: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/146.jpg)
The Review Model
app.js
First lets create a new model to represent a Review.
App.Product = DS.Model.extend({ title: DS.attr('string'), price: DS.attr('number'), description: DS.attr('string'), isOnSale: DS.attr('boolean'), image: DS.attr('string')});
App.Review = DS.Model.extend({ text: DS.attr('string'), reviewedAt: DS.attr('date')});
![Page 147: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/147.jpg)
Create Associations app.js
});
App.Review = DS.Model.extend({ text: DS.attr('string'),
});
reviews: DS.hasMany('review'
product: DS.belongsTo('product')
, {async: true})
Allows reviews to be lazy loaded
reviewedAt: DS.attr('date')
App.Product = DS.Model.extend({ title: DS.attr('string'), price: DS.attr('number'), description: DS.attr('string'), isOnSale: DS.attr('boolean'), image: DS.attr('string')
![Page 148: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/148.jpg)
Creating our Review Fixturesapp.js
We’ll use higher IDs so we can differentiate them
text: "Started a fire in no time!" }, { id: 101,
} ];
text: "Not the brightest flame, but warm!"
App.Review.FIXTURES = [ { id: 100,
![Page 149: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/149.jpg)
Mapping Reviews to a Productapp.js
text: "Started a fire in no time!" }, { id: 101,
text: "Not the brightest flame, but warm!"
product: 1,
product: 1,
App.Review.FIXTURES = [ { id: 100,
} ];
![Page 150: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/150.jpg)
Mapping a Product to Reviewsapp.js
Need to use an array to list out all reviews
App.Product.FIXTURES = [ { id: 1, title: 'Flint', price: 99, description: 'Flint is…', isOnSale: true, image: 'flint.png', reviews: [100,101] } ];
![Page 151: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/151.jpg)
Loop Over All Reviewsindex.html
Loop over all reviews and display them
<script type="text/x-handlebars" data-template-name='product'> <h1>{{title}}</h1> <p>{{description}}</p> <p>Buy for ${{price}}</p>
<h3>Reviews</h3> <ul>
{{ }}<li>{{review.text}}</li>
{{/each}} </ul>
</script>
#each review in reviews
![Page 152: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/152.jpg)
Easier Loop Variablesindex.html
Within the loop, you can reference the current review
<script type="text/x-handlebars" data-template-name='product'> <h1>{{title}}</h1> <p>{{description}}</p> <p>Buy for ${{price}}</p>
<h3>Reviews</h3> <ul>
{{ }}#each reviews<li>{{text}}</li>
{{/each}} </ul>
</script>
![Page 153: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/153.jpg)
Loops With {{else}}index.html
Add a default for when there are no reviews
<script type="text/x-handlebars" data-template-name='product'> <h1>{{title}}</h1> <p>{{description}}</p> <p>Buy for ${{price}}</p>
<h3>Reviews</h3> <ul>
{{ }}#each reviews<li>{{text}}</li>
{{else}} <li><p class='text-muted'> <em>No reviews yet. Be the first to write one!</em> </p></li>
{{/each}} </ul>
</script>
![Page 154: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/154.jpg)
Demo works! Show all reviews
![Page 155: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/155.jpg)
![Page 156: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/156.jpg)
Switching to REST
Let’s switch our application adapter back to REST
App.ApplicationAdapter = DS.RESTAdapter.extend();
![Page 157: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/157.jpg)
Ember Data hit the /products URL to get JSON data for our products route
![Page 158: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/158.jpg)
Asynchronous JSONhttp://example.com/products
{ "products": [ { "id": 1, "title": "Flint", "price": 99, "description": "Flint is…", "isOnSale": true, "image": "/assets/products/flint.png", "reviews": [100,101] }, { … } ], "reviews": [ { "id": 100, "product": 1, "text": "Started a fire in no time!" }, … ] }
This JSON file could be generated or hardcoded
![Page 159: CodeSchool-Emberjs](https://reader036.vdocuments.net/reader036/viewer/2022062222/5695cf9f1a28ab9b028ed5f7/html5/thumbnails/159.jpg)