EmberJS

Learning Resources

Official Docs

EmberJS Guides

EmberJS API

Ember CLI

Lists

Top 5 Best Resources for EmberJS

EmberWatch Tutorials

Tutorials

getting-started-with-ember-js-using-ember-cli

http://www.sitepoint.com/getting-started-with-ember-and-ember-cli/

Books in my iBooks Library

The PacktPub books have code files than can be downloaded from the website.

Ember.js Web Development with Ember CLI from PacktPub

Mastering Ember.js from PacktPub.

Ember CLI 101 from leanpub.com.

Ember.js Guides from leanpub.com.

Ember.js Guides Plus from leanpub.com.

Core Concepts

These are features of Ember’s objects. See the Ember.js Web Development with Ember CLI book for more information.

Mixins

Reusable code that can be shared amongst your other modules (classes).

Computed Properties

A Method that returns a value.

Getters and Setters

Use to access properties of an Ember class.

Observers

Code that is triggered by an event (when a property’s value changes).

Binding

When the value of an object’s property actually comes from a different object.

Routing

A route is a url path and what should be done when that URI is requested. The route will specify two things:

A resource is a group of routes. i.e. user/, user/1, user/1/edit, user/1/delete, etc.

/app/router.js holds your Router Map, which is used to determine which Route to use.

Because one of Route’s jobs is to get your data, that is where you will place additional logic (say filtering the data source). Put it in app/routes/path.js

Ember Magical Bits

ES6 Modules (import/export)

First, a bit of history. Asynchronous module definition (AMD) is a standard by which Javascript code is encapsulated and can have dependencies. This code can then be asynchronously loaded at run time. This was developed because Javascript doesn’t have a clean way to write classes nor manage dependencies. RequireJS is one implementation (and loader) of AMD modules.

The next version of Javascript (ECMAScript 6) attempts to resolve this through a new Module specification. By default anything you declare in a file in a ES6 project is not available outside that file. You have to use the export keyword to explicitly make it available. This bears repeating: If you attempt to create a global variable using:

var foo = 'bar';

it will be available to the code inside the same *.js file, but not anywhere else.

This is new technology, and it is not available in browsers yet. However we can use it today with the use of a transpiler that converts ES6 syntax into plain Javascript.

jQuery

Ember uses jQuery. If you need to call jQuery then use this syntax to access Ember’s jQuery instance:

Ember.$('your selector').method();

The URL

Ember will use HTML5 Pushstate for browsers that support it. This let’s you stay on the same page, but change the URL when accessing a different route. Users will be able to bookmark a deep link and get back to the same spot. They only problem here is those routes do not physically exist on your server so you’ll need to use rewrite rules, a fallback resource, or similar function of the web server.

If the browser doesn’t support Pushstate, then hashes are used on the URL (I think).

Rewrite Rules for Apache and Nginx

Nginx and Apache rewrites to support HTML5 Pushstate in pure Backbone.js (or other JS MV*) Application.

Posted on May 17th, 2012 in Apachebackbonenginx | 4 Comments »

HTML5 pushstate is awesome. It enables you to change the URL of your site dynamically without refreshing the page (goodbye hashes!). Libraries like Backbone have great support for this. Unfortunately if a user bookmarks or refresh a page on an app that’s using HTML5 pushstate, it makes a request to the server for that deep linked content. Here are the rewrites for Nginx and Apache to internally redirect that call to the same html file. Browser thinks its a unique page but it’s the same.

Apache

In your vhost :

<IfModule mod_rewrite.c>
	RewriteEngine On     
	RewriteBase /     
	RewriteRule ^index\.html$ - [L]     
	RewriteCond %{REQUEST_FILENAME} !-f     
	RewriteCond %{REQUEST_FILENAME} !-d     
	RewriteRule . /index.html [L]  
</IfModule>

Note: A different blog post suggested this instead:

I found a bunch of examples on the web of Apache rewrite rules that people are using for AJAX-based HTML5-history-using sites. All of them didn't work for me. I don't know why. But I thought it was Ember's fault. It wasn't. So I spun my wheels for a while blaming the router. It wasn't. It's just that there are some strange examples of rewrite rules on the web for AJAX-based HTML5-history-using sites.

Below is what worked for me. I wanted to send every request for URLs to index.html, except for certain subdirectories (js, css, img, svc). If you do this in the root of your Apache config, you might need to specify a forward slash.

Options +FollowSymLinks 
RewriteEngine On 
RewriteBase / 
RewriteRule ^(js|css|img|svc)($|/) - [L] 
RewriteRule ^(.*)$ index.html [L]

Nginx

rewrite ^(.+)$ /index.html last;

Note that once you have this in place your server no longer reports 400 errors as all requests pull up the index page. To work around this you can create a 404 in a Backbone route:

routes: {     
	// Other routes     
	"*path"  : "notFound"   
},     
notFound: function(path) {     
	// Load 404 template, probably of a cute animal.   
}

Passing Data to Templates

Ember component templates have a corresponding component module (Javascript file). So, if you need to pass a variable to the template, set it in the module first like this:

import Ember from 'ember';

export default Ember.Component.extend({
	actions: {
		editTodo: function() {
			this.set('isEditing', true);
		},
		acceptChanges: function() {
			this.set('isEditing', false);
			this.sendAction('acceptChanges', this.get('todo'));
		},
		deleteTodo: function(todo) {
			this.sendAction('deleteTodo', todo);
		}
	}
});

Then to use it in your template, reference the variable directly. e.g.

<li class="{{if todo.isCompleted 'completed'}}">
	{{#if isEditing}}
		{{input type="text" class="edit" value=todo.title focus-out="acceptChanges" insert-newline="acceptChanges"}}
	{{else}}
		{{input type="checkbox" checked=todo.isCompleted class="toggle"}}
		<label {{action "editTodo" on="doubleClick"}}>{{todo.title}}</label><button {{action "deleteTodo" todo}} class="destroy"></button>
	{{/if}}
</li>

Database Connectivity

Normally your data is stored in a database, but it is possible to use a local data store. Ember calls this Fixture Data.

First create an adapter (see above).

You don't need Ember data

Here’s something you might not know about Ember.js: It doesn’t come default with a data library. It may sound a little strange that a model-view-controller framework doesn’t come prepackaged with what a Rails developer would think of as model. In fact, a lot of the early complaints leveled at Ember (in the days when Ember Data was undergoing significant, break-your-application changes, like, all the time) was that if Data wasn’t ready, what was the point of using Ember at all?

App.UserRoute = Ember.Route.extend({
model: function(params) {
    return this.store.find(user, params.user_id);
  }
});

That code is using Ember Data. But it doesn’t have to be. See, the misunderstanding is that the model hook needs to return a proper Ember Model object. The truth is, it could return a plain JSON object and Ember would be just as happy. I could just do this…

App.UserRoute = Ember.Route.extend({
  model: function(params) {
    return {
      first_name: "Eric",
      last_name : "Sipple"
    };
  }    
});

…and our Controller gets a Model just the same. I use Ember Data because it provides a way to persist that data, and gives access to a really nice REST adapter, but there are a lot of people who are more than happy to deal with the REST parts on their own, and build a data object model that suits them better than what Ember Data does.

Ember needs data, sure, but it doesn’t need Ember Data.

 

Components

Still trying to figure this out, but I think Components have replaced both Controllers and Views.

Controllers

I've not talked about controllers becasue they are being depreceated from Ember so why would you want to learn about them? In short controllers were used to decorate a template, show the temporary state of elements (component) on the page. Temporary state is the state of a element on the page that you don't want to be saved permenantly in your model, for example if we are editing a todo, we'd show an <input>box rather than a <label>. We most probably wouldn't want to save the editing state on our model so that it's premanantly available, therefore it's temporary and that decoration is handled by a controller. In the future of Ember, templates should be a collections of components (elements), and components will look after their own decoration/temporary state so a controller becomes redundant in most cases. Please forget all about controllers.

Views

Views have been replaced with Components in most cases now. Keep that in mind when reading on...

Where does it go: view or controller?

Okay, so if Ember has Views, but doesn’t use them to display anything, what exactly do they do? My misunderstanding of Ember Views stuck around longer than almost anything else in the framework, and I’m still untangling things I did wrong because of it. Views are very easy to use for things they aren’t meant for. Specifically, it’s easy to start putting things in the View that really belong in the Controller, and vice versa.

Luckily, the “What are Views?” question is pretty easy to answer. There are two things you might use them for:

  1. Creating reusable components; and
  2. Setting up logic to handle events.

If your users had profile pictures, and you wanted to display those pictures on lots of different pages (y’know, like not just on the user profile page), you might want to set that up as a View. Especially if you wanted that profile picture component to have some event logic behind it. Say you wanted people to be able to click the picture to pop up a larger version of the image. Your View could wait for a click event to hit the picture, then execute whatever logic you want as a result.

Hold up, though. This is where I got turned around and put code in all the wrong places. A View is perfect for catching the browser event, but most of what you want to do as a result would go in the Controller.

Basically, your View catches the click, then sends the event up to the Controller.

App.ProfilePhotoView = Ember.View.extend({
  click: function(evt) {
    this.get('controller').send('expandProfilePhoto');
  }
});

App.UserController = Ember.ObjectController.extend({
  actions: {
    expandProfilePhoto: function() {
      // Get the expanded picture and display it
      // We'll talk more about what to do here later
    }
  }
});

See that actions property in the UserController? Any methods you define in there can be called by the View with send.

Ember won’t stop you from putting a lot of logic into that click event that really belongs elsewhere, but you’ll save yourself a lot of headaches if you let the Controller handle it.

Updating Fields

Do not directly update fields on the page; instead you should bind that field to the controller (or model?) and then update that instead.

Content Security Policy (CSP)

The relatively new CSP functionality does not want you to put inline styles on the DOM because it can be a security hole. If you can not change the source code to use, say, classes instead, then add a contentSecurityPolicy property to the /config/environment.js file.

module.exports = function(environment) {
	var ENV = {
	modulePrefix: 'logic-model',
	environment: environment,
	baseURL: '/',
	locationType: 'auto',
	EmberENV: {
		FEATURES: {
		// Here you can enable experimental features on an ember canary build
		// e.g. 'with-controller': true
		}
	},
	APP: {
		// Here you can pass flags/options to your application instance
		// when it is created
	}, 
	contentSecurityPolicy: {
		'style-src': "'self' 'unsafe-inline'"
	}
};