[repost ]Ember.js 技巧、诀窍和最佳实践

original:http://colobu.com/2014/09/26/Emberjs-tips-tricks-and-best-practices/#

目录 [−]

  1. 通用
    1. 核心概念
    2. 命名约定
    3. 带Binding后缀的属性自动转为Ember.Binding对象
    4. View vs. Component

Ember.js是一款用来创建炫酷的Web应用程序的JavaScript MV* 框架。 正像AngularJS,Backbone.js一样正在广泛的应用于现代的Web开发中, 知名用户包括 Yahoo!, Groupon, 和 ZenDesk.
总的来说, Ember.js还在推广之中, 国内使用它做开发的还比较少, 官方的文档也不是很完备。 所以这篇文章记录了我使用Ember中收集的一些技巧,诀窍和最佳实践, 并且会不断的更新。

想了解Ember.js和其它JavaScript框架的区别, 可以看这篇文章: AngularJS vs. Backbone.js vs. Ember.js

通用

核心概念

Template: describes the user interface of your application by Handlebars。
Router: The router translates a URL into a series of nested templates, each backed by a model.
Route: A route is an object that tells the template which model it should display.
Model: A model is an object that stores persistent state.
Controller: A controller is an object that stores application state. A template can optionally have a controller in addition to a model, and can retrieve properties from both.
Component: A component is a custom HTML tag whose behavior you implement using JavaScript and whose appearance you describe using Handlebars templates.

命名约定

Ember.js 由Yehuda Katz创建, 他还是jQuery, Ruby on Rails 和 SproutCore核心开发组的成员。 就像Katz其它项目一样, 命名约定(convention over configuration)被广泛使用。
你可以查看这篇文章了解Ember.js的命名: Ember命名规则

Binding后缀的属性自动转为Ember.Binding对象

valueBinding: "MyApp.someController.title" will create a binding from MyApp.someController.title to the value property of your object instance automatically. Now the two values will be kept in sync.

单向绑定: bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles")

View vs. Component

一句话, 尽量使用Component而不是View

Contrarily to Ember views, an Ember component is not connected to a related Ember Controller, since it is self contained, in which regards both the data and events that it handles. In this sense, components are easier to reuse in different places of the application, as well as in different applications.
http://raulbrito.github.io/articles/thoughts-on-ember-views-vs-components/

Controller

转到其它页面

1
2
3
4
aController.transitionToRoute(‘blogPosts’);
aController.transitionToRoute(‘blogPosts.recentEntries’);
aController.transitionToRoute(‘blogPost’, aPost);
aController.transitionToRoute(‘blogPost’, 1);

转到指定的url在测试和调试的时候也可以使用,正式产品中还少用到。

1
2
aController.transitionToRoute(‘/’);
aController.transitionToRoute(‘/blog/post/1/comment/13′);

访问其它Controller. needs属性

1
2
3
4
5
6
7
App.CommentsController = Ember.ArrayController.extend({
needs: [‘post’],
postTitle: function(){
var currentPost = this.get(‘controllers.post’); // instance of App.PostController
return currentPost.get(‘title’);
}.property(‘controllers.post.title’)
});

needs定义为此controller要访问的其它controllers的数组。
嵌套的controller也可以访问:

1
2
3
4
5
6
App.CommentsNewController = Ember.ObjectController.extend({
});
App.IndexController = Ember.ObjectController.extend({
needs: [‘commentsNew’]
});
this.get(‘controllers.commentsNew’); // instance of App.CommentsNewController

使用send调用定义的action

1
2
3
4
5
6
7
8
9
10
App.WelcomeRoute = Ember.Route.extend({
actions: {
playTheme: function() {
this.send(‘playMusic’, ‘theme.mp3′);
},
playMusic: function(track) {
//
}
}
});

主动触发property变动事件

propertyDidChange, propertyWillChange 即使你没有调用getset也能触发事件。

Route

一些钩子hook

  • activate Router进入此route时
  • beforeModel 在model之前调用
  • model 获取model数据
  • afterModel 当model获取到。 主要获取model时使用的是async/promise语法。
  • renderTemplate 渲染模版的钩子
  • setupController 为当前route设置钩子

controllerFor

在route中得到其它的controller对象。参数为the name of the route or controller。

modelFor得到父Route的model

1
2
3
4
5
6
7
8
9
10
11
App.Router.map(function() {
this.resource(‘post’, { path: ‘/post/:post_id’ }, function() {
this.resource(‘comments’);
});
});
App.CommentsRoute = Ember.Route.extend({
afterModel: function() {
this.set(‘post’, this.modelFor(‘post’));
}
});

transitionTo, intermediateTransitionTo

跳转到另外的route. The route may be either a single route or route path:

1
2
3
4
this.transitionTo(‘blogPosts’);
this.transitionTo(‘blogPosts.recentEntries’);
this.transitionTo(‘blogPost’, aPost);
this.transitionTo(‘blogPost’, 1);

refresh 刷新本route及子route的model

渲染非默认的模版

1
2
3
4
5
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render(‘favoritePost’);
}
});

Model

使用Ember.Objectextend定义新类

1
2
3
4
5
App.Person = Ember.Object.extend({
say: function(thing) {
alert(thing);
}
});

_super()父类的方法。

创建实例: var person = App.Person.create();

计算属性Computed Properties

computed properties let you declare functions as properties.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get(‘firstName’) + ‘ ‘ + this.get(‘lastName’);
}.property(‘firstName’, ‘lastName’)
});
var ironMan = App.Person.create({
firstName: “Tony”,
lastName: “Stark”
});
ironMan.get(‘fullName’); // “Tony Stark”

设置计算属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: function(key, value, previousValue) {
// setter
if (arguments.length > 1) {
var nameParts = value.split(/\s+/);
this.set(‘firstName’, nameParts[0]);
this.set(‘lastName’, nameParts[1]);
}
// getter
return this.get(‘firstName’) + ‘ ‘ + this.get(‘lastName’);
}.property(‘firstName’, ‘lastName’)
});

@each计算

1
2
3
4
5
6
7
8
9
10
11
12
App.TodosController = Ember.Controller.extend({
todos: [
Ember.Object.create({ isDone: true }),
Ember.Object.create({ isDone: false }),
Ember.Object.create({ isDone: true })
],
remaining: function() {
var todos = this.get(‘todos’);
return todos.filterBy(‘isDone’, false).get(‘length’);
}.property(‘todos.@each.isDone’)
});

数组元素的每一个更新 (CUD或者数组重新被赋值)都会触发重新计算。

observers 是同步的

运行一次Ember.run.once

Observers 在对象初始化之前不会被触发。如果想init时被触发,加上.on(\'init\')

1
2
3
4
5
6
7
8
9
App.Person = Ember.Object.extend({
init: function() {
this.set(‘salutation’, “Mr/Ms”);
},
salutationDidChange: function() {
// some side effect of salutation changing
}.observes(‘salutation’).on(‘init’)
});

增加observer:

1
2
3
person.addObserver(‘fullName’, function() {
// deal with the change
});

Ember.computed('aaa', function(){}), Ember.observer('aaa', function () {})

可以写为 function(){}.property('aaaa'), function(){}.observers('aaa')

reopen覆盖

1
2
3
4
5
6
Person.reopen({
isPerson: true,
say: function(thing) {
this._super(thing + “!”);
}
});

Person.create().get(‘isPerson’) // true

架构

Store

1
2
3
App.Store = DS.Store.extend();
App.register(‘store:main’, App.Store);
App.inject(‘view’, ‘store’, ‘store:main’);

model 和 record

record是model的一个实例

adapter

负责将record和数据持久化后台结合起来。
DS.RESTAdapter, FixtureAdapter

Serializer

A serializer is responsible for turning a raw JSON payload returned from your server into a record object.
负责将一个纯的JSON转换成record对象。

属性定义时,attr()类型可以不设置

后台服务器返回啥就是啥。也可以指定类型。类型只能是string,number,booleandate
Date遵循 ISO 8601. 例如: 2014-05-27T12:54:01。

1
2
3
firstName: attr(),
lastName: attr(),
birthday: DS.attr(‘date’)

One-to-One, One-to-Many和Many-to-Many. hasMany

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
App.User = DS.Model.extend({
profile: DS.belongsTo(‘profile’)
});
App.Profile = DS.Model.extend({
user: DS.belongsTo(‘user’)
});
App.Post = DS.Model.extend({
comments: DS.hasMany(‘comment’)
});
App.Comment = DS.Model.extend({
post: DS.belongsTo(‘post‘)
});
App.Post = DS.Model.extend({
tags: DS.hasMany(‘tag’)
});
App.Tag = DS.Model.extend({
posts: DS.hasMany(‘post‘)
});
var belongsTo = DS.belongsTo,
hasMany = DS.hasMany;
App.Comment = DS.Model.extend({
onePost: belongsTo(‘post‘),
twoPost: belongsTo(‘post‘),
redPost: belongsTo(‘post‘),
bluePost: belongsTo(‘post‘)
});
App.Post = DS.Model.extend({
comments: hasMany(‘comment’, {
inverse: ‘redPost’
})
})

增删改查

  1. createRecord
1
2
3
4
5
6
7
8
9
10
var store = this.store;
var post = store.createRecord(‘post’, {
title: ‘Rails is Omakase’,
body: ‘Lorem ipsum’
});
store.find(‘user’, 1).then(function(user) {
post.set(‘author’, user);
});
  1. deleteRecord/save 或者 destroyRecord
    store.find(‘post’, 1).then(function (post) {
    post.deleteRecord();
    post.get(‘isDeleted’); // => true
    post.save(); // => DELETE to /posts/1
    });

// OR
store.find(‘post’, 2).then(function (post) {
post.destroyRecord(); // => DELETE to /posts/2
});

  1. push到store的缓存
1
2
3
4
5
6
this.store.push(‘album’, {
id: 1,
title: “Fewer Moving Parts”,
artist: “David Bazan”,
songCount: 10
});
  1. save
1
2
3
4
5
6
7
8
9
var onSuccess = function(post) {
self.transitionToRoute(‘posts.show’, post);
};
var onFail = function(post) {
// deal with the failure here
};
post.save().then(onSuccess, onFail);
  1. find
    根据参数内部用find,findAllfindQuery实现。
1
2
3
4
var posts = this.store.find(‘post’); // => GET /posts
var posts = this.store.all(‘post’); // => no network request
var aSinglePost = this.store.find(‘post’, 1); // => GET /posts/1
var peters = this.store.find(‘person’, { name: “Peter” }); // => GET to /persons?name=’Peter’

model的一些方法

incrementProperty
changedAttributes

Adapter的 URL Conventions

Action HTTP Verb URL
Find GET /people/123
Find All GET /people
Update PUT /people/123
Create POST /people
Delete DELETE /people/123

namespace

1
2
3
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: ‘api/1′
});

Requests for App.Person would now target /api/1/people/1.

normalizeHash

如果想将JSON中的lastNameOfPerson关联model的lastName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
App.Person = DS.Model.extend({
lastName: DS.attr(‘string’)
});
App.PersonSerializer = DS.RESTSerializer.extend({
normalizeHash: {
lastNameOfPerson: function(hash) {
hash.lastName = hash.lastNameOfPerson;
delete hash.lastNameOfPerson;
return hash;
}
}
});

Adapter的其它属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: ‘api/1′
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: ‘https://api.example.com’
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
return Ember.String.underscore(type);
}
});
MyCustomAdapterAdapter = DS.RESTAdapter.extend({
defaultSerializer: ‘-default’
});

定制Transformations

除了内建类型string, number, boolean, and date,你可以定义新类型。

1
2
3
4
5
6
7
8
9
10
11
12
App.CoordinatePointTransform = DS.Transform.extend({
serialize: function(value) {
return [value.get(‘x’), value.get(‘y’)];
},
deserialize: function(value) {
return Ember.create({ x: value[0], y: value[1] });
}
});
App.Cursor = DS.Model.extend({
position: DS.attr(‘coordinatePoint’)
});

数组类型

1
2
3
4
5
6
7
8
9
10
11
12
App.ArrayTransform = DS.Transform.extend({
deserialize: function (serialized) {
‘use strict’;
return Ember.A(serialized);
},
serialize: function (deserialized) {
‘use strict’;
return deserialized ? deserialized.toArray() : [];
}
});

View

定义view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{{#view “clickable”}}
This is a clickable area!
{{/view}}
App.ClickableView = Ember.View.extend({
click: function(evt) {
this.get(‘controller’).send(‘turnItUp’, 11);
}
});
App.PlaybackController = Ember.ObjectController.extend({
actions: {
turnItUp: function(level){
//Do your thing
}
}
});

定制view元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
App.MyView = Ember.View.extend({
tagName: ‘span’
});
App.MyView = Ember.View.extend({
classNames: [‘my-view‘]
});
App.MyView = Ember.View.extend({
classNameBindings: [‘isUrgent’],
isUrgent: true
});
<div class=“ember-view is-urgent”>
App.MyView = Ember.View.extend({
classNameBindings: [‘isUrgent:urgent’],
isUrgent: true
});
App.MyView = Ember.View.extend({
classNameBindings: [‘isEnabled:enabled:disabled’],
isEnabled: false
});
App.MyView = Ember.View.extend({
tagName: ‘a’,
attributeBindings: [‘href’],
href: “http://emberjs.com”
});
1
2
3
{{view “info” tagName=“span”}}
{{view “info” id=“info-view”}}
{{view “alert” classBinding=“isUrgent priority”}}

内建的view

  • Ember.Checkbox
  • Ember.TextField
  • Ember.TextArea
  • Ember.Select

Template

数据枚举 Ember.Enumerable

forEach

1
2
3
4
[1,2,3].forEach(function(item) {
console.log(item);
console.log(item, this.indexOf(item));
});

可枚举的类型

  • Array: 实现纯javascript Array并且实现 Enumerable interface
  • Ember.ArrayController
  • Ember.Set

toArray()得到纯javascript数组

firstObject, lastObject

MAP

1
2
3
4
5
6
var words = [“goodbye”, “cruel”, “world”];
var emphaticWords = words.map(function(item) {
return item + “!”;
});
// [“goodbye!”, “cruel!”, “world!”]
1
2
3
4
5
6
7
8
9
10
11
12
var hawaii = Ember.Object.create({
capital: “Honolulu”
});
var california = Ember.Object.create({
capital: “Sacramento”
});
var states = [hawaii, california];
states.mapBy(‘capital’);
//=> [“Honolulu”, “Sacramento”]

filter

1
2
3
4
5
6
7
var arr = [1,2,3,4,5];
arr.filter(function(item, index, self) {
if (item < 4) { return true; }
})
// returns [1,2,3]
1
2
3
4
5
6
7
8
9
10
11
12
13
Todo = Ember.Object.extend({
title: null,
isDone: false
});
todos = [
Todo.create({ title: ‘Write code’, isDone: true }),
Todo.create({ title: ‘Go to sleep’ })
];
todos.filterBy(‘isDone’, true);
// returns an Array containing only items with `isDone == true`

Aggregate

everysome判断集合所有元素或者部分元素是否满足条件。
也可以

1
2
people.isEvery(‘isHappy’, true) // false
people.isAny(‘isHappy’, true) // true

Helper

bind class
class可以是

  • a string return value of an object’s property. <img \{\{bind-attr \class="view.someProperty}}>
  • a boolean return value of an object’s property. true插入类名, false移除类名或替换类名 <img \{\{bind-attr \class="view.someBool:class-name-if-true"}}> <img \{\{bind-attr \class="view.someBool:class-name-if-true:class-name-if-false"}}>
  • a hard-coded value <img \{\{bind-attr \class=":class-name-to-always-apply"}}>

复合型: <img \{\{bind-attr \class=":class-name-to-always-apply view.someBool:class-name-if-true view.someProperty"}}>

each helper

1
2
3
4
5
6
7
8
9
10
11
12
13
Developers = [{name: ‘Yehuda’},{name: ‘Tom’}, {name: ‘Paul’}];
{{#each Developers}}
{{name}}
{{/each}}
{{#each person in Developers}}
{{person.name}}
{{/each}}
{{#each DeveloperNames}}
{{this}}
{{/each}}

集合为空时使用\{\{#each}}

1
2
3
4
5
{{#each person in Developers}}
{{person.name}}
{{else}}
<p>Sorry, nobody is available for this task.</p>
{{/each}}

指定渲染用的view

1
2
3
{{#view App.MyView }}
{{each view.items itemView\class=“App.AnItemView”}}
{{/view}}

默认遍历controller的属性,可以指定itemController:

1
2
3
4
5
6
7
8
9
10
App.DeveloperController = Ember.ObjectController.extend({
isAvailableForHire: function() {
return !this.get(‘model.isEmployed’) && this.get(‘model.isSeekingWork’);
}.property(‘isEmployed’, ‘isSeekingWork’)
})
{{#each person in developers itemController=“developer”}}
{{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
{{/each}}

if-else

1
2
3
4
5
{{#if message.isTypeSuccess}}
……
{{else}}
……
{{/if}}

另外还提供了unless

1
2
3
{{#unless hasPaid}}
You owe: ${{total}}
{{/unless}}

outlet

一个模版占位符。

1
2
3
4
5
6
7
8
9
{{outlet ‘favoritePost’}}
{{outlet ‘posts’}}
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render(‘favoritePost’, { outlet: ‘favoritePost’ });
this.render(‘posts’, { outlet: ‘posts’ });
}
});
1
2
3
4
5
6
{{outlet view=’sectionContainer‘}}
App.SectionContainer = Ember.ContainerView.extend({
tagName: ‘section’,
classNames: [‘special’]
});

partial 渲染另外一个页面而不改变上下文

1
2
{{foo}}
{{partial “nav”}}

render 使用包含的上下文

{{render “navigation”}}

Calling {{render}} from within a template will insert another template that matches the provided name. The inserted template will access its properties on its own controller (rather than the controller of the parent template).

view

{{view}} inserts a new instance of an Ember.View into a template passing its options to the Ember.View’s create method and using the supplied block as the view’s own template.

view, partialrender的区别

General

Helper Template Model View Controller
{{partial}} Specified Template Current Model Current View Current Controller
{{view}} View’s Template Current Model Specified View Current Controller
{{render}} View’s Template Specified Model Specified View Specified Controller

Specific

Helper Template Model View Controller
{{partial “author”}} author.hbs Post App.PostView App.PostController
{{view “author”}} author.hbs Post App.AuthorView App.PostController
{{render “author” author}} author.hbs Author App.AuthorView App.AuthorController

with changes scope, as

1
2
3
{{#with person}}
Welcome back, <b>{{firstName}} {{lastName}}</b>!
{{/with}}

link-to (routeName, context, options) String
提供tagName: \{\{#link-to 'photoGallery' tagName="li"}} Great Hamster Photos\{\{/link-to}}
自动添加\class="active"
指定model: \{\{#link-to 'photoGallery' aPhoto}} \{\{aPhoto.title}}\{\{/link-to}}, for dynamic segments或者多个model或者model id: \{\{#link-to 'photoGallery' aPhotoId}} \{\{aPhoto.title}}\{\{/link-to}}

input

\{\{input type="text" value=firstName disabled=entryNotAllowed size="50"}}
支持action: \{\{input action="submit"}}
支持的actions: enter insert-newline escape-press focus-\in focus-out key-press\{\{input focus-\in="alertMessage"}}

checkbox: \{\{input type="checkbox" name="isAdmin"}}

自定义helper

简单语法

1
2
3
4
Ember.Handlebars.helper(‘highlight’, function(value, options) {
var escaped = Handlebars.Utils.escapeExpression(value);
return new Ember.Handlebars.SafeString(‘<span \class=”highlight”>’ + escaped + ‘</span>’);
});

使用\{\{highlight name}}

依赖参数

1
2
3
Ember.Handlebars.helper(‘fullName’, function(person) {
return person.get(‘firstName’) + ‘ ‘ + person.get(‘lastName’);
}, ‘firstName’, ‘lastName’);

使用{{fullName person}}

定制view helper

1
Ember.Handlebars.helper(‘calendar’, App.CalendarView);

使用\{\{calendar}}或者\{\{view "calendar"}}

Component

HTML代码代替hbs模版

在Component和View的实现时,可以直接使用Ember.Handlebars.compile直接写HTML代码,不用定义一个hbs模版文件。

1
template: Ember.Handlebars.compile(“Greetings {{name}}”)

定义组件

  1. template必须以components/开头。比如组件0的模版为components/blog-post
  2. 组件名必须包含破折号dash 。blog-post合法但是post不合法。
  3. 继承Ember.Component或子类。 blog-post的类为App.BlogPostComponent

组件的钩子(Hook)函数

传给组件参数

\{\{blog-post title=name}}, name是外部对象的属性
一句话componentProperty=outerProperty

定制组件的属性

类似view。

从组件发送action给其它应用

When a component is used inside a template, it has the ability to send actions to that template’s controller and routes. These allow the component to inform the application when important events, such as the user clicking a particular element in a component, occur.
组件\{\{my-button action="showUser"}}

1
2
3
4
5
App.MyButtonComponent = Ember.Component.extend({
click: function() {
this.sendAction();
}
});

`this.sendAction(‘action’, param1, param2);

1
2
3
4
5
6
7
8
9
10
11
12
App.ConfirmButtonComponent = Ember.Component.extend({
actions: {
showConfirmation: function() {
this.toggleProperty(‘isShowingConfirmation’);
},
confirm: function() {
this.toggleProperty(‘isShowingConfirmation’);
this.sendAction(‘deleteAction’, this.get(‘param’));
}
}
});
1
2
3
4
5
6
7
{{! templates/components/confirm-button.handlebars }}
{{#if isShowingConfirmation}}
<button {{action “confirm”}}>Click again to confirm</button>
{{else}}
<button {{action “showConfirmation”}}>{{title}}</button>
{{/if}}
1
2
3
4
5
{{! index.handlebars }}
{{#each todo in todos}}
<p>{{todo.title}} {{confirm-button title=“Delete” deleteAction=“deleteTodo” param=todo}}</p>
{{/each}}

多action: \{\{user-form submit="createUser" cancel="cancelUserCreation"}}

 

[repost ]谷歌百度脸书IBM,人工智能四巨头2014盘点

original:http://www.huxiu.com/article/106064/1.html

2014年,人工智能得到了前所未有的关注, Eron Musk和霍金的“人工智能恶魔论”在学术界和产业界引发了激烈争论;资本对这个方向也是趋之若鹜,截止到2004年,有超过20亿美元的风险投资流入到基于认知技术研究的产品和服务里,超过100家的相关公司被互联网巨头收购。而对于普通用户来说,只有当那些科技巨头在人工智能领域实现布局,并将这些技术应用到具体的产品和服务中时,他们才能真正感受到人工智能带来的优势。而去年恰恰是这些科技巨头动作极其频繁的一年,接下来,本文将对谷歌、百度、Facebook和IBM四家科技公司在人工智能领域的布局和研究成果进行盘点。

 

谷歌

 

KK在谷歌创业初期跟拉里·佩奇聊过,已经有一个性能不错的搜索引擎,为什么还要做一个?拉里·佩奇说,不是要开发新的搜索引擎,我们要做的是人工智能。而对于“一家科技公司如何才能保住主导地位?” 佩奇认为,最好的方式就是投资未来。佩奇希望继续增强对未来科技的布局,继续以最不可思议的方式改变世界,而人工智能就是其中非常重要的一个方向。

 

1) 对DeepMind的收购及后续运作

 

2014年年初,谷歌以4亿美元的架构收购了深度学习算法公司——DeepMind,公司创始人哈萨比斯是一位横跨游戏开发、神经科学和人工智能等多领域的天才人物。7月,谷歌以DeepMind为主体与牛津大学的两支人工智能研究队伍建立了合作关系。

 

DeepMind也很快发布了研究成果,它在10月份公布了一种新的模拟神经网络,旨在模仿人类大脑的工作记忆原理,拥有更加强大的归纳整理和联想演绎等逻辑处理能力,从而带来更快的任务处理速度,还可以通过训练去自行处理任务,这种全新的深度学习算法可用于计算机视觉和语音识别等领域。

 

2)自动驾驶汽车

 

奇点大学的网络与计算部门负责人Brad Templeton认为,在接下来的10-20年里最具改变世界潜力的技术是自动驾驶汽车,而谷歌在这方面要领先于传统汽车厂商。

 

此前,谷歌的自动驾驶汽车已经完成了总计70万英里的高速公路无人驾驶巡航里程。在此基础上,谷歌于7月份推出了100辆原型车来执行小规模的市区道路测试,这是自动驾驶行业首次进行的规模化城市道路测试。谷歌的原型车安装了17个感应装置,搜集来的信息能快速建立起一个半径200公尺的3D信息图,让车辆对外部环境进行分析判断,实现360度的全方位防护。谷歌预计在2014年底前打造200辆测试车,并在寻求与汽车制造商进行合作,计划五年内实现无人驾驶汽车的量产和投放市场。

 

3) 以Nest为基础的智能家居生态系统建设

 

谷歌于2014年1月份以32亿美元收购了智能家居制作商Nest,该公司主要提供智能恒温器和智能烟雾探测器,并已经拥有 100 多项专利,200 多项专利已在美国专利局备案,另有 200 多项专利准备备案。6月份,谷歌通过Nest花费5.55亿美元收购了基于云端的家庭监控公司Dropcam,10月份,又收购了智能家居中枢控制设备公司Revolv,该公司将参与Nest的开放计划“Works with Nest”。Nest对于产品的研发也是马不停蹄,于2014年年底一口气发布了四款产品,包括一款室内自动恒温计、两款网络监控摄像头和一款烟雾警报器。

 

谷歌已经意识到智能家居领域将是未来人工智能应用的一个重要市场,所以通过一系列并购、开放平台的建立、软件硬件一体化来打造这个生态系统,而Nest创始人Tony  Fadell一篇文章的标题《欢迎回家》也反映出了谷歌在智能家居领域布局的前瞻性和决心。

 

4) 在图形识别和语音识别研究领域的重大进展

 

2014年,谷歌开始了开发一套能够整合公司海量数据的语音系统,这个正处在测试阶段将会使计算机从本质上“听懂”和“思考”人们向谷歌设备输入的语音。这个团队将前馈神经网络替换成了递归神经网络,提高了系统对语音信息的存储和处理能力,并能够使用上下文、物理定位及其它方式对谈话者的真正含义进行预测,就像人在谈话时大脑所做的一样。

 

在图像识别方面,谷歌在8月份收购了一家图片分析公司Jetpac。Google研究院也发表了一篇文章,表明未来Google的图形识别引擎不仅仅能够识别出照片的对象,还能够对整个场景进行简短而准确的描述。除此之外,谷歌一直在积极吸引图像识别和计算机视觉方面的专家参与到谷歌的项目研究中来,比如说向研究计算机视觉和模式识别的助理教授Devi Parikh授予了谷歌内部研究奖项Faculty Research Awards和 9万美元的无限制基金,并允许她直接同谷歌的其他研究者和工程师进行合作。

 

根据德勤发布的一份报告显示,Google在2014年将语音识别的精准度从2012年的84%提升到如今的98%,移动端Android系统的语音识别准确性提高了25%;计算机视觉技术也取得了突飞猛进的发展。如果以计算机视觉技术研究者设置的技术标准来看,自2010年到2014年,图像分类识别的精准度提高了4倍。

 

5)总结

 

总体看来,谷歌在人工智能的布局依然符合它“将全世界的信息联系起来并给出最佳处理结果”的使命,在这一目标下,谷歌的行为可以大致分成两个路径,第一是覆盖更多的用户使用场景,从谷歌传统业务覆盖的互联网、移动互联网延伸到智能家居、自动驾驶、机器人(2013年收购了8家机器人公司)等领域,从而抓取到更多信息,这可以看做是信息积累和输入的过程。第二个方面是不知疲倦的做好底层人工智能技术的积累,研发更加高级的深度学习算法,增强图形识别和语音识别能力,从而能对第一阶段收集到的信息进行更好的处理和反馈,这可以看做是信息的处理和用户服务的输出过程。在这两个过程下,谷歌就将人工智能渗透到了其各种产品的方方面面,从而为用户带来更多的使用场景和更加智能的功能。

 

百度

 

中国的搜索巨头百度公司与谷歌有些类似,都是以互联网搜索为基础,都是技术导向型公司,而且在人工智能领域的布局也是走在互联网行业的前列。我在文章《搜索引擎到人工智能的终极演进》中提到了目前的搜索引擎看以看作是未来人工智能的雏形,依托于搜索本身积累的用户和数据,再加上云服务、深度学习等技术,很有可能实现从传统的互联网搜索服务向人工智能高级形态的进化。而百度的Andrew Ng也在演讲中提到了人工智能的正循环——拥有深度学习算法之后,将不再惧怕海量数据,反而会因为数据的增长而取得更好的效果,而这些效果将直接体现在图像搜索、语音识别等具体的互联网服务中,从而为用户提供更好服务并吸引更多用户,这又会产生更多数据。因此,百度在人工智能领域的布局既表现出了其作为技术公司的敏感性和前瞻性,同时也可以看做是百度走向未来的必由之路。

 

1)引进Andrew Ng及组建北美研究院

2014年5月,深度学习专家Andrew Ng(吴恩达)加盟百度,并负责同期成立的北美研究中心。由于相对于传统互联业务,人工智能的技术门槛相对较高,而对于相关技术人才的引起也就显得尤为重要。在谷歌和Facebook相继聘用了Geoffrey Hinton和Yann LeCun之后,百度将另一位人工智能大师Andrew Ng引入,这体现出百度与美国互联网巨头谷歌和Facebook在人工智能领域展开竞争的勇气和实力,而北美研究中心的建立也表明百度将继续与硅谷的互联网巨头争夺人工智能领域的人才。而Andrew Ng与余凯、张潼、AdamCoates、徐伟等组成的顶尖团队将会成为百度发展人工智能坚强后盾。

 

2)大数据积累和平台开放

 

大数据是人工智能的基础,而作为天然的大数据企业,百度拥有强大的数据获取能力和数据挖掘能力,百度副总裁王劲更是将百度技术布局描绘为一张剑形图,人工智能、大数据等技术化作剑锋。百度除了做好数据积累和挖掘以外,还加快了大数据平台的开放步伐,于2014年4月发布了大数据引擎,向外界提供大数据存储、分析和挖掘技术,而且在医疗、交通和金融领域有了具体应用。

 

2014年7月14日,百度凭借自身的大数据技术14场世界杯比赛的结果预测中取得全中的成绩,击败了微软和高盛。2014年9月,百度正式发布整合了大数据、百度地图LBS的智慧商业平台,旨在更好在移动互联网时代为各行业提供大数据解决方案。

 

3)语音识别和图像识别

 

2014年12月,美国《福布斯》发布文章称,吴恩达及研究团队发明了一种新的语音识别方法,这款基于深度学习的名为“Deep Speech”语音识别系统可以在嘈杂环境下实现将近 81% 的辨识准确率。卡耐基梅隆大学工程学助理研究教授Ian Lane对其的评价是“百度研究院最近的工作有可能颠覆语音识别在未来的应用效果。” 吴恩达表示,该语音识别系统采用深度学习算法取代了原来的模型,在递归神经网络或者模拟神经元阵列中进行训练,让语音识别系统更加简单。同时这套系统还使用了Nvidia等芯片制造商出品的多枚图形处理器(GPU),这些处理器通过并行连接,能够用比普通计算机处理器更快的速度训练语音识别模型,从而提高工作效率。

 

在图像识别方面,余凯称摄像头成为连接人和世界信息的重要入口之一。而百度也一直在利用深度学习技术来提高图像识别的精度。2014年9月,百度云结合百度深度学习研究院提供的人脸识别及检索技术,推出云端图像识别功能。11月,百度发布了基于模拟神经网络的“智能读图”,可以使用类似人脑思维的方式去识别、搜索图片中的物体和其他内容。

 

4)人工智能算法和云计算

 

百度大脑既需要人工智能算法,也需要云计算中心提供硬件支持。百度大脑通过深度学习来模拟人类大脑的神经元,参数规模达到百亿级别,构建了世界上最大规模的深度神经网络。

 

百度在国内拥有十几座云计算中心,为满足人工智能在计算和存储上的高要求,还投入使用了4万兆交换机,并在探索10万兆交换机。百度还是全球首家将GPU用于人工智能和深度学习领域、并规模化商用ARM服务器的公司。百度将这些整合在一起,就形成强大的存储计算能力,从而可以进行多样的并行计算,支持生成、配置针对不同应用和场景网络结构,从而为人工智能提供有力的硬件支持。

 

5)自动驾驶项目

 

2014年9,百度宣布已经与宝马正式签署合作协议,共同研发自动化驾驶技术。其中,百度的三维地图及相关数据服务也将被融入宝马的车辆导航系统中,为自动驾驶汽车提供技术支撑。双方计划在接下来三年时间内,合作研究高度自动化驾驶在中国道路环境下面临的技术挑战,通过智能技术加强道路行驶安全性,减少交通事故及人员伤亡。

 

6)总结

 

百度在人工智能领域的布局可以总结为三点,第一,具有战略眼光,与世界科技巨头保持同步;第二,自身技术基因又使其非常注重技术人才的引进和人工智能底层技术的积累;第三,互联网入口的地位和丰富的产品线使得人工智能技术能够迅速落地,转化成具体的产品和服务。也正因如此,2014年11月首届百度技术节才会以“奇点临近 技术引领未来”为主题,展望如何通过人工智能来改变世界。

 

Facebook

 

Facebook在人工智能领域的布局主要围绕着其用户的社交关系和社交信息来展开,在2013年加入公司的深度学习鼻祖Yann LeCun的帮助下,公司的图像识别技术和自然语言处理技术大幅提升。

 

Yann LeCun是纽约大学终身教授,是卷积神经网络领域的重要推动者,而该技术的最主要应用就是图像识别的自然语言处理,这与Facebook的需求和已经积累的数据类型非常匹配。在Yann LeCun的帮助下,2014年Facebook的DeepFace技术在同行评审报告中被高度肯定,其脸部识别率的准确度达到97%。而他领导的Facebook人工实验室研发的算法已经可以分析用户在Facebook的全部行为,从而为用户挑选出其感兴趣的内容。而不久后,那些算法还能够分析用户在状态帖子中输入的文本,进而自动提示相应的标签。他还表示,想在Facebook中建立一个智能助手,如果用户上传的照片中又令人尴尬的内容会进行识别和提醒。用LeCun的原话来说就是——Facebook人工智能实验室的职责就是给予用户更多的在线身份控制权,而不是削弱你的控制。

 

IBM

 

IBM目前看起来可能没有谷歌和Facebook这样酷,但其在人工智能领域有着丰富的底蕴,并在2014年采取了若干举措。主要是开放了Watson平台和发布了模拟人脑芯片SyNAPSE。

 

1)超级计算机沃森的开放战略

 

2014年1月初,IBM宣布组建“Watson Group”,旨在进一步开发、商用及增强“Watson”及其他认知技术,还将给其投入10亿美元资金用于研发和其他投资。现在,IBM宣称如今的Watson比2011年参加《危险边缘》“智能”了2400%,而且尺寸也已经从过去的卧室那么大缩减成三个披萨盒那么大。同时,IBM还推出了两项Watson数字顾问服务,一项用于帮助企业从海量数据获得洞见,另一项则旨在使得数据可视化。Gartner预计在2015年之前,将会形成一个由Watson衍生出来的巨大的智能顾问市场;而法国农业信贷银行预测那些系统创造的收入将在2018年占到IBM总收入的12%以上。

 

2014年3月,已经在医疗和金融行业都有所应用的Watson又开始与纽约基因中心(New York Genome Center, NYGC)的合作。8月,IBM声称Watson即将被用于科学研究,目前,测试科学假设和理论常常需要花费几天甚至几个月时间。不过,借助沃森的“Discovery Advisor”项目,这样的工作可以更快地完成。

 

2014年5月,IBM通过Watson Group收购了人工智能创业公司Cognea,该公司开发了一个认知计算和对话式人工智能平台,为用户提供个性化虚拟助手服务。IBM对于 Cognea的定位是能够理解用户的个性化需求,将互动提升至一个新的水平。

 

本年,Watson也被部署在IBM去年收购的云计算基础设施业务Softlayer上,成为IBM与亚马逊、谷歌、和微软、等大型科技公司在云计算领域展开竞争的武器。

 

2)人脑模拟芯片SyNAPSE发布

 

2014年8月,IBM再度发布能模拟人类大脑的SyNAPSE(Systems of Neuromorphic Adaptive Plastic Scalable Electronics,即“自适应塑料可伸缩电子神经形态系统”)芯片,相比前一代原型,新的芯片已达到量产要求,并且拥有100万个“神经元”内核、2.56亿个“突触”内核以及4096个“神经突触”内核,而功率则仅有70毫瓦,该芯片能够模仿人脑的运作模式,更擅长进行模式识别,而且低功耗,在认知计算方面要远远穿过传统计算架构。

 

3)总结

IBM在人工智能领域的布局还是在围绕着Watson和SyNAPSE做文章,这代表着他们在人工智能领域长时间技术积累,同时IBM也在越来越开放,希望能像其他科技巨头一样,建立一个真正的开放性的技术平台,真正组建一个生态系统,因为人工智能领域的技术门槛相对较高,所以在这个时代来临时,或许会成为IBM逆转的好时机。

[repost ]How to install and enable EPEL repo in RHEL/CentOS/Oracle Linux?

original:http://www.linuxnix.com/2014/07/how-to-install-and-enable-epel-repo-in-rhel-centos-oracle-scentific-linux.html

What is EPEL repo?

EPEL(Extra Packages for Enterprise Linux) is a repo developed by Fedora project to ensure that there is a quality 3rd party packages available for enterprise users such as people who are using RHEL, Cent OS, Oracle Linux and Scientific Linux. These are highly used enterprise Linux OS which are shipped with default, thoroughly checked and officially conformed packages so that there will be less bugs in the installed software in enterprise environment. But there are situations where a 3rd party software which is of great use in enterprise world is not in the official list. For example Puppet is a great configuration tool which is not in default repo. The solution to this is enable EPEL repo on enterprise Linux box.

Some of the well known packages which are not included in official CentOS, Red-hat, Oracle and Scientific Linux repos are as follows

ansible – SSH-based configuration management, deployment, and task execution system
cfengine – A systems administration tool for networks
nagios – Nagios monitors hosts and services and yells if something breaks
puppet – A network tool for managing many disparate systems
rsnapshot – Local and remote file system snapshot utility
p7zip – Very high compression ratio file archiver
clamav – Anti-virus software
wine – A compatibility layer for windows applications
ncftp – Improved console FTP client
hddtemp – Hard disk temperature tool
openvpn – A full-featured SSL VPN solution
Pound – Reverse proxy and load balancer
fail2ban – Ban IPs that make too many password failures

To know about available software in this repo you can go to below link.

http://dl.fedoraproject.org/pub/epel/6/i386/repoview/

How to install EPEL repo in RHEL?

If you are using any RHEL based Linux such as Centos, Oracle and Scientific Linux we have to follow below process to install it. This same for versions 4.x, 5.x, 6.x and 7.x. Just replace 6 with your respective version number.

For RHEL 6.8 64 bit version:

rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

For RHEL 6.8 PPC64:

Example:

[root@diskstuff ~]# rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
Retrieving http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
warning: /var/tmp/rpm-tmp.mk9iVg: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing…                ########################################### [100%]    1:epel-release           ########################################### [100%] [root@diskstuff ~]#

Note: We no need to use wget or some other software to download this package, we can just directly point http link to rpm command, which will install directly from the specified location.

Check if you can install any package which are listed above.

[root@diskstuff ~]# yum install fail2ban
Loaded plugins: fastestmirror, refresh-packagekit
Loading mirror speeds from cached hostfile
epel/metalink                                                                                                           | 3.7 kB     00:00
* base: mirror.web24.net.au
* epel: mirror.web24.net.au
* extras: mirror.web24.net.au
* updates: mirror.web24.net.au
epel                                                                                                                    | 4.4 kB     00:00
epel/primary_db                                                                                                         | 5.1 MB     00:03
Setting up Install Process
Resolving Dependencies
–> Running transaction check
—> Package fail2ban.noarch 0:0.8.11-2.el6 set to be updated
–> Processing Dependency: python-inotify for package: fail2ban-0.8.11-2.el6.noarch
–> Running transaction check
—> Package python-inotify.noarch 0:0.9.1-1.el6 set to be updated
–> Finished Dependency ResolutionDependencies Resolved

===============================================================================================================================================
Package                                Arch                           Version                              Repository                    Size
===============================================================================================================================================
Installing:
fail2ban                               noarch                         0.8.11-2.el6                         epel                         221 k
Installing for dependencies:
python-inotify                         noarch                         0.9.1-1.el6                          epel                          50 k

Linuxnix-free-e-book

Transaction Summary
===============================================================================================================================================
Install       2 Package(s)
Upgrade       0 Package(s)

Total download size: 271 k
Installed size: 1.0 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): fail2ban-0.8.11-2.el6.noarch.rpm                                                                                 | 221 kB     00:00
(2/2): python-inotify-0.9.1-1.el6.noarch.rpm                                                                            |  50 kB     00:00
———————————————————————————————————————————————–
Total                                                                                                          139 kB/s | 271 kB     00:01
warning: rpmts_HdrFromFdno: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
epel/gpgkey                                                                                                             | 3.2 kB     00:00 …
Importing GPG key 0x0608B895 “EPEL (6) <epel@fedoraproject.org>” from /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
Is this ok [y/N]: y
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Warning: RPMDB altered outside of yum.
Installing     : python-inotify-0.9.1-1.el6.noarch                                                                                       1/2
Installing     : fail2ban-0.8.11-2.el6.noarch                                                                                            2/2

Installed:
fail2ban.noarch 0:0.8.11-2.el6

Dependency Installed:
python-inotify.noarch 0:0.9.1-1.el6

Complete!
[root@diskstuff ~]#

If you are unable to install or you find that epel is not enable check if EPEL repo is enabled or not

 

[root@diskstuff ~]# cat /etc/yum.repos.d/epel.repo
[epel] name=Extra Packages for Enterprise Linux 6 – $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6

 

Once you made enabled=1 and refresh the repo by using yum clean all, you can install all the software in the EPEL repo.

[repost ]Ember without Ember Data

original:http://eviltrout.com/2013/03/23/ember-without-data.html

The concepts in this article are still true, but I’ve recorded a screencast showing how to use ember without ember data using ember-cli and the latest version of Ember. It goes beyond the contents of this article, showing how to create an adapter, store and even your own identity map. Check it out!


Ember Data is a persistence layer for Ember.Js. Unlike Ember, which currently has a candidate for a 1.0 release, Ember Data is still very much a work in progress. This has been a source of confusion for people who are learning Ember, as the two frameworks are complimentary but currently exist in different realms of stability.

Ember Data has ambitious goals, and it has come a long way in the last year. If you’re the kind of programmer who loves working on upcoming stuff, you might find it exhilarating. On the other hand, it is completely understandable if you’d want to avoid it. Deprecations and changing APIs can be frustrating and time consuming.

One thing that is not always clear to people starting with Ember is that Ember works perfectly well without Ember Data! Trust me on this: Discourse doesn’t use Ember Data for persistence and it’s working quite well. Moreover, using AJAX with Ember is something that is not difficult to do.

Ember Models that are just Objects

Ember includes an object model that most people with an OOP background should find familiar. A subclass ofEmber.Object works very well for a data model.

Here’s what a class might look like to represent a link from reddit:

App.RedditLink = Ember.Object.extend({});

You could then easily instantiate it and use getters and setters to access its properties:

var link = App.RedditLink.create();
link.set('url', 'http://eviltrout.com');
console.log(link.get('url')); // http://eviltrout.com

If you like, when you construct your model instance, you can pass it a regular Javascript object with the properties rather than setting them one at a time:

var discourseLink = App.RedditLink.create({
  title: "Discourse",
  url: "http://www.discourse.org"
});

console.log(discourseLink.get('title')); // Discourse

Here’s how you’d bind those properties to a handlebars template:

Title: {{title}}
Url: {{url}}

Once bound to a template like this, if you called set on your model, it would automatically update the HTML.

Accessing Reddit via JSONP

Data models are a lot more exciting when you fill them real data. Let’s write a method that finds the links from a subreddit. Reddit provides a JSONP API that we can access via jQuery:

$.getJSON("http://www.reddit.com/r/" + subreddit + "/.json?jsonp=?", function(response) {
  // response contains the JSON result
});

The response from reddit’s API includes the colleciton of links under data.children, but their properties are under an additional data attribute. We can loop through them like so, creating instances of RedditLink as we go:

var links = response.data.children.map(function (child) {
  return App.RedditLink.create(child.data);
});
// links now contains all our `RedditLink` objects!

$.getJSON is an asynchronous call. It follows that our model’s finder method will have to be asynchronous as well. One common approach to dealing with this is to pass a callback function to our finder method. When the$.getJSON call finishes, it can execute the callback with the result. What happens, though, when you need to handle the errors? You’d have to supply two callbacks: one for the error callback and one for the success callback.

Promises

This is all much cleaner to do with Promises. Promises are objects you return from your functions. They contain a then method that you can call when the operation is complete.

The nice thing about this is you don’t have to supply your callbacks to your function – you just attach them to the Promise object that your function returns. It ends up being a lot cleaner and simpler to follow. Additionally, Promises can be chained, so that the result of one promise is only passed through to the next function in the chain once it is complete.

jQuery conveniently return promises from all its AJAX calls, so we can just make use of it. Here’s how our finder looks, returning a promise:

App.RedditLink.reopenClass({

  findAll: function(subreddit) {
    return $.getJSON("http://www.reddit.com/r/" + subreddit + "/.json?jsonp=?").then(
      function(response) {
        return response.data.children.map(function (child) {
          return App.RedditLink.create(child.data);
        });
      }
    );
  }

});

Notice that we’re returning the result of $.getJSON, but also calling then on it. This means that the Promise that our findAll method returns will eventually resolve to our list of RedditLink objects. Here’s how you could you could call it and log the results from the subreddit /r/aww:

App.RedditLink.findAll('aww').then(function (links) {
  console.log(links); // logs the array of links after it loads
});

Putting it all together

I’ve created a github project that puts all the code from this blog entry together.

The code for the application is quite short, which I think reflects Ember’s greatest strength: as a developer you have to write less code to get stuff done.

I implore you to not be scared off by Ember Data’s current state. Ember itself is quite stable, and it’s easy to get started with AJAX calls like this today.

[repost ]How to represent arrays within ember-data models?

original:http://stackoverflow.com/questions/12168570/how-to-represent-arrays-within-ember-data-models

Answer:

Well… It was a little bit difficult but mixing all answers in this post I made it work.

Firstly, you should create a transform for the new type “array”:

DS.ArrayTransform = DS.Transform.extend({
  deserialize: function(serialized) {
    return (Ember.typeOf(serialized) == "array")
        ? serialized 
        : [];
  },

  serialize: function(deserialized) {
    var type = Ember.typeOf(deserialized);
    if (type == 'array') {
        return deserialized
    } else if (type == 'string') {
        return deserialized.split(',').map(function(item) {
            return jQuery.trim(item);
        });
    } else {
        return [];
    }
  }
});

App.register("transform:array", DS.ArrayTransform);

Now, in your model, just use it as another attr:

App.myModel = Ember.Model.extend({
    name : DS.attr('string'),
    cont : DS.attr('array')
}

And we are done. Remember, when adding elements to the array, to use pushObject.

In a controller:

this.get('model.cont').pushObject('new Item');

I hope this helps someone.

 

Answer2:

I use a raw transform, which looks like this in ember-data revision 11:

DS.RESTAdapter.registerTransform('raw', {
    deserialize: function(serialized) {
        return serialized;
    },  
    serialize: function(deserialized) {
        return deserialized;
    }   
});

Then, within a model, I do this:

App.MyModel = Ember.Model.extend({
    anArray: DS.attr('raw')
});

and can use anArray like a regular array anywhere.

Answer 3:

Here is an example of creating a custom array type in Ember-Data (version 10):

DS.JSONTransforms.array =

  # If the outgoing json is already a valid javascript array
  # then pass it through untouched. In all other cases, replace it
  # with an empty array.  This means null or undefined values
  # automatically become empty arrays when serializing this type.

  serialize: (jsonData)->
    if Em.typeOf(jsonData) is 'array' then jsonData else []


  # If the incoming data is a javascript array, pass it through.
  # If it is a string, then coerce it into an array by splitting
  # it on commas and trimming whitespace on each element.
  # Otherwise pass back an empty array.  This has the effect of
  # turning all other data types (including nulls and undefined
  # values) into empty arrays.

  deserialize: (externalData)->
    switch Em.typeOf(externalData)
      when 'array'  then return externalData
      when 'string' then return externalData.split(',').map((item)-> jQuery.trim(item))
      else               return []

Now you can use the custom type in a model attribute:

App.CalenderWeek = DS.Model.extend
  selected_days = DS.attr('array')

And now when you fetch a record with:

App.CalendarWeek.find(1)

both of these incoming json records will deserialize correctly into an Array:

{ selected_days: ['Monday', 'Tuesday', 'Saturday'] }

or

{ selected_days: 'Monday, Tuesday, Saturday' }

[repost ]Getting Into Ember.js

original:

There are a lot of JavaScript libraries available, and most are really good at providing the traditional DOM-centric interactions that your typical websites need. But when it’s time to build a manageable code base for a single-page app, that’s where a whole suite of new frameworks come in to smooth things out.

The old saying is true: “Use the best tool for the task.”

It’s not that traditional libraries like jQuery can’t help you build desktop-like experiences, it’s just not the use-case for it and is missing things like data-binding, event routing and state management. Sure, you can probably cobble together a bunch of plugins to achieve some of that functionality, but starting with a framework that’s been specifically built from the ground up to tackle these specific problems, in my opinion, makes more sense. The old saying is true: “Use the best tool for the task.”

I recently did an interview with the Ember.js team; it was motivated by my desire to get to know what I’ve come to call “the new hotness”: Ember.js.

Ember fits the bill for what I’ve described above, and does so in a fashion that reminds of a lot of how jQuery allows developers to get up and running quickly. The team has purposely taken steps to abstract a lot of the complexities inherent in designing and building Model/View/Controller based applications using years of expertise and knowledge gained from building large-scale apps.

What I’d like to do is help get you up to speed with Ember.js, via a multi-part article series which will gradually introduce you to the concepts of the framework. We’ll start off with the usual intro (which happens to be this post), and then gradually ramp up to building a full application. The great part is that this will also help me reinforce the concepts that I’ve already learned, and maybe pick up some new techniques along the way! I’ll do my best to have the Ember.js team review this material for accuracy and perhaps even contribute some nuggets to it.

Before we continue, a heads up: Ember.js does a lot of magic for you. There are times when you’ll look at the code and say “Huh? How’d it do that?” I’ve been there and I’ll do my best to distill things, but I’m not going to dive into the bowels of Ember’s framework code. Instead, I’ll discuss how you can leverage its tools and API to build your app.

So let’s kick this off.

Core Concepts

Ember.js is not a framework for building traditional websites.

The first thing to keep in mind is that Ember.js is not a framework for building traditional websites. Libraries like jQuery and MooTools are a great fit for that. If you’re considering Ember.js, then the assumption is that you’re looking to build desktop-like experiences – especially scalable ones. In fact, the slogan for the framework is “a framework for developing ambitious web applications” which tells you it’s clearly not your daddy’s JavaScript library.

I mentioned previously that Ember leverages the MVC pattern for promoting proper code management and organization. If you’ve never done MVC-based development, you should definitely read up on it. Nettuts+ has a great article on the topic here. For those of you familiar with the concepts, you should feel at home. The one thing I’ve heard consistently is that making the shift from Backbone to Ember.js is actually easy because Ember does a lot of the heavy lifting for you, while still maintaining the code organization patterns that those developers are accustomed to.

Ember also relies on client-side templates… a LOT. It uses the Handlebars templating library which provides expressions that allow you to create dynamic HTML-based templates. An Ember developer can bind data to these embeddable expressions and dynamically change the display of their app on the fly. For example, I can create a template that can receive an array of people and display them in an unordered list:

1
2
3
4
5
<ul>
{{#each people}}
<li>Hello, {{name}}!</li>
{{/each}}
</ul>
Notice the “#each” expression that works as a loop directive, enumerating over each element of the “people” array and replacing the “{{name}}” expression with an actual value. It’s important to note that the double brackets are tokens used by Handlebars to identify expressions. This is a small example, and we’ll dive into more detail later.

Handlebars is an incredibly powerful client-side templating engine and I would recommend reviewing not only the Ember guides, but the Handlebars website itself to get a full grasp of the options available. You’ll be using it quite a bit.

Setting up Ember

Ember.js relies on additional libraries, so you’ll need to go grab a copy of jQuery and Handlebars. But, wait, didn’t I say that jQuery and Ember play in different spaces? Well, yeah I did, but here’s the thing: the Ember team is all about not reinventing the wheel. They chose jQuery to do what it does best: work with the DOM. And that’s a good thing, since jQuery is really good at that. It’s also why they went with Handlebars, which is an excellent templating library that happened to be written by Yehuda Katz, who is an Ember core team member.

The easiest way to get the files you need is to go to the Ember.js Github repo and pull down the Starter Kit. It’s a boilerplate for you to start off with. At the time of this writing, it contains:

Ember 1.0 RC1
Handlerbars 1.0 RC3
jQuery 1.9.1
There’s also a basic html template that is coded to include all of the associated libraries (jQuery, Ember, etc.) and along with an example of a Handlebars template and “app.js”, which includes code for kicking off a basic Ember app.

1
2
3
4
<script src=”js/libs/jquery-1.9.1.js”></script>
<script src=”js/libs/handlebars-1.0.0-rc.3.js”></script>
<script src=”js/libs/ember-1.0.0-rc.1.js”></script>
<script src=”js/app.js”></script>
Just note that app.js isn’t part of the framework. It’s a plain ole JavaScript file; you can name it anything you want. And, while we’ll use it for the purposes of this tutorial series, down the road, you’ll likely end up splitting your JavaScript into multiple files just like you would for any other site or app. Also, Ember doesn’t expect a specific directory structure for your framework files.

When you look at the Starter Kit code, it may look like your typical website code. In some respects, you’re right! Once we start organizing things, though, you’ll see how building an Ember app is different.

The Lay of Ember Land

Before you start hacking at code, it’s important to understand how Ember.js works and that you grok the moving parts that make up an Ember app. Let’s take a look at those parts and how they relate to each other.

Templates

Templates are a key part of defining your user interface. As I mentioned previously, Handlebars is the client-side library used in Ember and the expressions provided by the library are used extensively when creating the UI for your application. Here’s a simple example:

1
2
3
<script type=”text/x-handlebars”>
<h2><strong>{{firstName}} {{lastName}}</strong></h2>
</script>
Notice that the expressions are mixed into your HTML markup and, via Ember, will dynamically change the content displayed on the page. In this case, the {{firstName}} and {{lastName}} placeholders will be replaced by data retrieved from the app.

Handlebars offers a lot of power, via a flexible API. It will be important for you to understand what it offers.

Routing

An application’s Router helps to manage the state of the application.

An application’s Router helps to manage the state of the application and the resources needed as a user navigates the app. This can include tasks such as requesting data from a model, hooking up controllers to views, or displaying templates.

You do this by creating a route for specific locations within your application. Routes specify parts of the application and the URLs associated to them. The URL is the key identifier that Ember uses to understand which application state needs to be presented to the user.

1
2
3
App.Router.map( function() {
this.route( ‘about’ ); // Takes us to “/about”
});
The behaviors of a route (e.g.: requesting data from a model) are managed via instances of the Ember route object and are fired when a user navigates to a specific URL. An example would be requesting data from a model, like this:

1
2
3
4
5
App.EmployeesRoute = Ember.Route.extend({
model: function() {
return App.Employee.find();
}
});
In this case, when a user navigates to the “/employees” section of the application, the route makes a request to the model for a list of all employees.

Models

An object representation of the data.

Models are an object representation of the data your application will use. It could be a simple array or data dynamically retrieved from a RESTful JSON API, via an Ajax request. The Ember Data library offers the API for loading, mapping and updating data to models within your application.

Controllers

Controllers are typically used to store and represent model data and attributes. They act like a proxy, giving you access to the model’s attributes and allowing templates to access them to dynamically render the display. This is why a template will always be connected to a controller.

The main thing to remember is that, while a model retrieves data, a controller is what you’ll use to programmatically expose that data to different parts of your application. While it may seem that models and controllers are tightly coupled, in fact, models, themselves, have no knowledge of the controllers that will use them later on.

You can also store other application properties that need to persist but don’t need to be saved to a server.

Views

Views in Ember.js are meant to manage events around user interaction and translate them into events that have meaning within your application. So, if a user clicks on a button to delete an employee, the view is responsible for interpreting that native browser click event and processing it appropriately within the context your application’s current state.
Advertisement
Naming Conventions

One of the ways that Ember.js helps to minimize the amount of code needed and handle things for you behind the scenes is through naming conventions. The way that you define and name your routes (and resources) impacts the naming of your controllers, models, views and templates. For example, if I create a route, called “employees”:

1
2
3
App.Router.map( function() {
this.resource( ‘employees’ );
});
I would then name my components, like this:

Route object: App.EmployeesRoute
Controller: App.EmployeesController
Model: App.Employee
View: App.EmployeesView
Template: employees
Using this naming convention serves a dual purpose. First, it gives you a semantic relationship between like components. Secondly, Ember can automatically create the necessary objects that may not exist (e.g.: a route object or a controller) and wire them up for use in your application. This is the “magic” that I mentioned earlier. In fact, this is specifically what Ember does at the global Application level, when you instantiate the Application object:

var App = Ember.Application.create();

That single line creates the default references to the application’s router, controller, view and template.

Route object: App.ApplicationRoute
Controller: App.ApplicationController
View: App.ApplicationView
Template: application
Going back to the “employees” route that I created above, what will happen is that, when a user navigates to “/employees” in your application, Ember will look for the following objects:

App.EmployeesRoute
App.EmployeesController
the employees template
If it doesn’t find them, it will create an instance of each but simply won’t render anything, since you haven’t specified a model to derive data from or a template to display the data with. This is why the naming convention is so important. It allows Ember to know how to handle the tasks associated with a specific route, without you having to wire things up manually.

Notice that, in the first example, I used the singular name, “Employee,” to define the model. That’s on purpose. The very nature of the name “Employees” dictates that I may be working with 0 to many employees, so it’s important to build a model that could provide the flexibility to return one employee or all employees. The singular naming convention of this model is not a requirement of Ember, as models themselves have no knowledge of the controllers that will use them later on. So you do have flexibility in naming them, but for consistency, sticking with this convention will make managing your code substantially easier.

Also, I chose to use the resource() method to define my route, because in this scenario, I would most likely have nested routes to manage detail pages for specific employee information. We’ll talk about nesting later in the series.

The key takeaway is that by using a consistent naming scheme, Ember can easily manage the hooks that bind these components together without your needing to explicitly define the relationships via a ton of code.

Full details of Ember’s naming conventions are provided on the project’s site and is a must-read.

Next Up: Building an App

In the next part of the series, we’ll dive into the code to create the basis for our application.

We’ve gone over the core concepts of Ember and discussed the key high-level aspects of the framework. In the next part of the series, we’ll dive into the code to create the basis for our application. In the interim, I want to again recommend that you begin looking at the documentation for Handlebars to get a feel for the expressions syntax. Also, if you’re really chomping at the bit to get into Ember, stay tuned to Tuts+ Premium, which will soon offer a full course that walks you through building an Ember-based application!

As I noted at the beginning of this article, Ember.js Core Team leads Yehuda Katz and Tom Dale reviewed this for accuracy, and gave it the thumbs up. Ember team approved! See you in a bit!

In my introductory article, I went over the basics of the Ember.js framework, and the foundational concepts for building an Ember application. In this follow-up article, we’ll dive deeper into specific areas of the framework to understand how many of the features work together to abstract the complexities of single-page application development.

I noted previously that the easiest way to get the files you need is to go to theEmber.js Github repo and pull down the start kit, and that still holds true. This boilerplate kit includes all the files that you’ll need to kickstart your Ember experience, so be sure to download it from this article.

The interesting thing is that the starter kit is also a great example of a very basic Ember app. Let’s walk through it to gain an understanding of what’s going on. Note that I’ll be digging deeper into specific areas later, so don’t worry if something doesn’t make immediate sense in this section. It’s more to give you a high-level understanding of the functionality before diving into the details.

Open index.html in your browser, and you’ll see the following:

Welcome to Ember.js

  • red
  • yellow
  • blue

This is not very exciting, I know, but if you look at the code that rendered this, you’ll see that it was done with very little effort. If we look at “js/app.js“, we see the following code:

At its most basic level, an Ember app only needs this one line to technically be considered an “app”:

This code sets up an instance of the Ember application object, along with a default application template, event listeners and application router. Take a second and try to think of the code you would normally have to write to create a global namespace, a client-side template, bind event handlers for global user interaction and include history & state management in your code. Yes, that one line does all of that. Let’s be clear, though: I’m not saying that it’s doing all of the work for you, but it is creating the foundation you’ll build upon, via one method call.

The next set of code sets up the behavior of a route, in this case, for the mainindex.html page:

Remember that routes are used to manage the resources associated with a specific URL within the application, and allows Ember to track the various states of individual pages. The URL is the key identifier that Ember uses to understand which application state needs to be presented to the user.

In this case, the root route is created by default in Ember. I could’ve also explicitly defined the route this way:

But Ember takes care of that for me for the “root” of my application. We’ll tackle routes in more detail later.

Going back to the following code:

In this case, when a user hits the site’s root, Ember will setup a controller that will load a sample set of data with a semantic name, called content. This data can later be used in the app, via this controller using that name. And that’s specifically what happens in index.html. Open the file and you’ll find the following:

This is a Handlebars client-side template. Remember that Handlebars is the templating library for Ember, and is vital to creating data-driven user interfaces for your app. Ember uses data attributes to link these templates to the controllers that manage your data, whether they’re specified via a route or as a standalone controller.

In my last article, I mentioned that naming conventions are important in Ember, and that they make connecting features easy. If you look at the template code, you’ll see that the name of the template (specified via the data-template-name attribute) is “index”. This is purposeful and is meant to make it easy to connect to the controller specified within the route of the same name. If we look at the route code once again, you’ll see that it’s called “IndexRoute” and inside of it is a controller with data being set:

The controller sets a datasource named “content” and loads it with an array of strings for the colors. Basically, the array is your model, and the controller is used to expose that attributes of the model.

The naming conventions allow Ember to link this route’s resources (e.g.: the controller with data) to the template specified by the same name. This gives the template access to the data exposed by the controller so it can render it using Handlebars’ directives. From there, the items in the array are looped over using Handlebars’ each directive and specifying the alias model which points to the datasource:

To be more precise, the data is populated into dynamically created list items, thus generating the markup for you on the fly. That’s the beauty of client-side templates.

I think this basic app highlights how Ember abstracts a lot of things for you. It is a bit of black magic though and it’s not always easy to grasp how things work. That actually happened to me and things didn’t quite click at first. Once you start understanding the relationships between the various components of the framework, it starts to make more sense. Let’s start from the ground up to get a better understanding of this.

I briefly touched on the Ember application object and the fact that it builds the foundation for your application. The Ember guides do an excellent job of outlining specifically what instantiating an Ember application object does:

  • It sets your application’s namespace. All of the classes in your application will be defined as properties on this object (e.g. App.PostsView andApp.PostsController). This helps to prevent polluting the global scope.
  • It adds event listeners to the document and is responsible for sending events to your views.
  • It automatically renders the application template, the root-most template, into which your other templates will be rendered.
  • It automatically creates a router and begins routing, based on the current URL.

So this simple statement:

wires up a whole ton of foundational pieces that your application will depend on. It’s important to note that App is not a keyword in Ember. It’s a normal global variable that you’re using to define the namespace and could be any valid variable name. From what I’ve seen, though, the variable name, App, is a commonly used convention in most Ember apps and is actually recommended to make it easier to copy and paste much of the sample code being created in the community.

Taking the list above, what Ember does, via that one line, is essentially create this code for you automatically behind the scenes:

So, while the starter kit didn’t explicitly define an application-scoped router, route or template, Ember ensured that they’re created and available so that the foundation of your app is set and available to you. It’s definitely okay to explicitly create the code. In fact, you may want to do so if you plan to pass data or set attributes for your instance of the application object.

Now you might be wondering about this “application template” getting automatically rendered and why you don’t see it in index.html. That’s because it’s optional to explicitly create the application template. If it’s in the markup, Ember will immediately render it. Otherwise, it carries on processing other parts of your application as normal. The typical use-case for the application template is defining global, application-wide user interface elements, such as header and footers.

Defining the application template uses the same style syntax as any other template except with one small difference: the template name doesn’t need to be specified. So defining your template like this:

or this:

gives you the same exact results. Ember will interpret a template with no data-template-name as the application template and will render it automatically when the application starts.

If you update index.html by adding this code:

You’ll now see that the contents of the header tag appears on top of the content of the index template. The Handlebars {{outlet}} directive serves as a placeholder in theapplication template, allowing Ember to inject other templates into it (serving as a wrapper of sorts), and allowing you to have global UI features such as headers and footers that surround your content and functionality. By adding the applicationtemplate to index.html, you’ve instructed Ember to:

  • Automatically render the application template
  • Inject the index template into the application template via the Handlebars{{outlet}} directive
  • Immediately process and render the index template

An important takeaway is that all we did was add one template (application), and Ember immediately took care of the rest. It’s these feature bindings that makeEmber.js such a powerful framework to work with.

Routing is arguably the most difficult concept to understand in Ember, so I’ll do my best to break it down to manageable steps. As a user navigates your application, there needs to be a method for managing the state of the various parts the user visits. That’s where the application’s router and location-specific routes come in.

The Ember router object is what manages this through the use of routes that identify the resources needed for specification locations. I like to think of the router as a traffic cop that’s directing cars (users) to different streets (URLs & routes). The routes, themselves, are tied to specific URLs and, when the URL is accessed, the routes resources are made available.

Looking at js/app.js again, you’ll notice that a route has been created for the root page (index):

However, there’s no router instance. Remember that Ember will create a router by default if you don’t specify one. It will also create a default route entry for the root of the application similar to this:

This tells Ember that, when the root of the application is hit, it should load the resources of a route object instance called IndexRoute if it’s available. This is why, despite no router instance being declared, the application still runs. Ember internally knows that the root route should be named IndexRoute, will look for it, and load its resources, accordingly. In this case, it’s creating a controller that will contain data to be used in the index template.

Since URLs are the key identifiers that Ember uses to manage the state of your application, each one will generally have their own route handler specified if resources need to be loaded for that section of the app. Here’s what I mean; suppose that you have an app with three sections:

  • Account: (URL: /account)
  • Profile (URL: /profile)
  • Gallery (URL: /gallery)

In most cases, each one of these sections will have its own unique resources that need to be loaded (e.g.: data or images). So you would create route handlers using the resource() method within Ember’s application router object instance like this:

This allows Ember to understand the structure of the application and manage resources, accordingly. The routes definitions will correlate to individual route object instances which actually do the heavy-lifting like setting up or interfacing controllers:

So in the example above, when a user visits “/gallery”, Ember.js instantiate the GalleryRoute route object, setup a controller with data and render the gallerytemplate. Again, this is why naming conventions are so important in Ember.

Your application may also have nested URLs, like /account/new

For these instances, you can define Ember resources that allow you to group routes together, like so:

In this example, we used the resource() method to group the routes together and the route() method to define the routes within the group. The general rule of thumb is to use resource() for nouns (Accounts and Account would both be resources even when nested) and route() for modifiers: (verbs like new and edit or adjectives like favorites and starred).

Apart from grouping the routes, Ember builds internal references to the controllers, routes and templates for each of the group routes specified. This is what it would look like (and again it touches on Ember’s naming conventions):

“/accounts”:

  • Controller: AccountsController
  • Route: AccountsRoute
  • Template: accounts (yes it’s lowercase)

“/accounts/new”:

  • Controller: AccountsNewController
  • Route: AccountsNewRoute
  • Template: accounts/new

When a user visits “/accounts/new” there’s a bit of a parent/child or master/detail scenario that occurs. Ember will first ensure that the resources for accounts are available and render the accounts template (this is the master part of it). Then, it will follow-up and do the same for “/accounts/new”, setting up resources and rendering the accounts.new template.

Note that resources can also be nested for much deeper URL structures, like this:

I’ve covered a lot of material in this post. Hopefully, it has helped to simplify some of the aspects of how an Ember application functions and how routes work.

We’re still not finished, though. In the next entry, I’ll dive into Ember’s features for pulling back data and making it available with your app. This is where models and controllers come in, so we’ll focus on understanding how the two work together.

I hope that you’re starting to see that Ember.js is a powerful, yet opinionated, framework. We’ve only scratched its surface; there’s more to learn before we can build something truly useful! We’ll continue using the Ember Starter Kit. In this portion of the series, we’ll review accessing and managing data within Ember.

In the last article, we worked with a static set of color names that were defined within a controller:

This allowed the controller to expose the data to the index template. That’s cute for a demo, but in real life, our data source will not be a hard-coded array.

This is where models comes in. Models are object representations of the data your application uses. It could be a simple array or data dynamically retrieved from a RESTful JSON API. The data itself is accessed by referencing the model’s attributes. So, if we look at a result like this:

The attributes exposed in the model are:

  • login
  • id
  • age
  • gender

Data itself is accessed by referencing the model’s attributes.

As you see from the code above, you could define a static store, but you’ll useEmber.Object for defining your models most of the time. By subclassingEmber.Object, you’ll be able to return data (e.g.: via an Ajax call) and define your model. While you can explicitly set data within a controller, it’s always recommended that you create a model in order to adhere to separation of concerns and code organization best practices.

Alternatively, you could use a sister framework called Ember Data. It is an ORM-like API and persistence store, but I need to stress that it is in a state of flux as of this writing. It has a lot of potential, but using Ember.Object is much safer at this time. Robin Ward, co-founder of Discourse, wrote a great blog post on using Ember without Ember Data. It outlines their process, which I’ll break down for you.

In the following example, I’m going to use the unofficial Hacker News API to pull JSON-based data from the news resource. This data will be stored in my model and later used by a controller to fill a template. If we look at the data returned from the API, we can understand the properties we’ll be working with:

I want to work with the items property, which contains all of the headlines and story information. If you’ve worked with SQL databases, think of each element of itemsas a record and the property names (i.e.: title, url, id, etc.) as field names. It’s important to grok the layout because these property names will be used as the attributes of our model object—which is a perfect segue into creating the model.

Ember.Object is the main base class for all Ember objects, and we’ll subclass it to create our model using itsextend() method.

To do this, we’ll add the following code to js/app.js immediately after the code that defines App.IndexRoute:

App.Item serves as the model class for the Hacker News data, but it has no methods to retrieve or manipulate that data. So, we’ll need to define those:

Let’s break down this code. First, we use Ember’s reopenClass() method to add our new methods to the App.Item class, and you pass it an object that contains our desired methods. For this example, we only need one method called all(): it returns all of the headlines from the Hacker News frontpage. Because jQuery is part of the deal with Ember, we have its simple Ajax API at our disposal. The API uses JSONP to return JSON data; so, I can just use $.getJSON() to make the request to:

The “callback=?” tells jQuery that this is a JSONP request, and the data (once it’s retrieved) is passed to an anonymous callback handler defined using jQuery’s promises functionality:

I can easily pump in my JSON data into an Ember object.

The response parameter contains the JSON data, allowing you to loop over the records and update the local items array with instances of App.Item. Lastly, we return the newly populated array when all() executes. That’s a lot of words, so let me summarize:

  • Create your new model class by subclassing Ember.Object using extend().
  • Add your model methods using reopenClass().
  • Make an Ajax call to retrieve your data.
  • Loop over your data, creating an Item object and pushing it into an array.
  • Return the array when the method executes.

If you refresh index.html, you’ll see nothing has changed. This makes sense because the model has only been defined; we haven’t accessed it.

Controllers act like proxies, giving you access to the model’s attributes and allowing templates to access them in order to dynamically render the display. In addition to accessing attributes from an associated model, controllers can also store other application properties that need to persist without saving to a server.

Currently, our app has the following controller (the one that defines a static data set):

We can directly associate our model with App.IndexRoute using the model method (AKA the model hook):

Remember that Ember defines your controller if you don’t explicitly define it yourself, and that is what’s happening in this case.

Behind the scenes, Ember creates IndexController as an instance of Ember.ArrayController, and it uses the model specified in the model method.

Now we just need to update the index template to access the new attributes. Opening index.html, we can see the following Handlebars template code:

With one small change (adding the title property), we can immediately see the titles returned from the Hacker News API:

{{item.title}}

If you refresh your browser now, you should see something similar to the following:

If you want to display more information, simply add more properties:

Refresh to see the updates you’ve made. That’s the beauty of Handlebars; it makes it trivial to add new data elements to the user interface.

As I mentioned before, controllers can also be used to define static attributes that need to persist throughout the life of your application. For example, I may want to persist certain static content, like this:

Here, I subclass Ember.ObjectController to create a new controller for my indexroute and template to work with. I can now go to index.html and update my template to replace the following:

with:

Models are object representations of the data your application uses.

Handlebars will take the specified attributes in my controller and dynamically replace the {{headerName}} placeholder with its namesake value. It’s important to reinforce two things:

  • By adhering to Ember’s naming conventions, I didn’t have to do any wiring to be able to use the controller with the index template.
  • Even though I explicitly created an IndexController, Ember is smart enough not to overwrite the existing model that’s been associated via the route.

That’s pretty powerful and flexible stuff!

Working with data in Ember isn’t difficult. In actuality, the hardest part is working with the various APIs that abound on the web.

The fact that I can easily pump in my JSON data into an Ember object makes management substantially easier—although I’ve never been a big fan of large data sets on the client-side, especially when represented as objects.

It’s something I’ll have to do more testing on, and I hope that Ember Data makes all of this trivial.

With that said, I briefly touched on templates in this article. They’re very important… so much so that I want to tackle this topic in its own article. So in the next article, we’ll go over how to leverage Handelbars to build your user interface and drill-down into the various directives the templating framework offers.

[repost ]9 THINGS YOU SHOULD KNOW BEFORE STARTING YOUR NEXT EMBER.JS AND EMBER DATA APPLICATION

original:http://bigemployee.com/9-things-you-should-know-before-starting-your-next-ember-js-and-ember-data-application/

If you are building a fairly complex web application, there is a high probability that you will have a lot of JavaScript code, and you would want to organize your code in some modular way that will be easier to maintain. Also at the same time you would also want to use some sort of a framework to simplify the process for you. But before getting there, let’s talk about how we got here at first place. In this video Robin Ward, co-founder of Discourse, talks about browser applications.

Building a fairly complex web application needs a very careful planning. Not just at the application level, but also at maintainability and efficiency level. Even if you are going to be the only person that’s going to work and maintain the code for a foreseeable future. Here are 9 things I thought you should know after creating your Hello World application and before creating your next application using Ember, especially if you are going to use Ember Data as your persistence library. Due to readers request, here is the code.

DEMODOWNLOAD SOURCE

1. Is Ember the right MVC framework for your project?

I leave this decision for you to find out. But this is definitely a question to ask. Here is a quote by Tom Dale, one of the founders of Ember at interview at Intercom on his view on Angular vs Ember that I think is just right for this section.

I think there are a lot of people for whom they just want to be on whatever the most popular bandwagon is, right? I think that if you’re choosing a JavaScript library purely based on popularity, I think you deserve what you get. But I think there are applications that Angular is really great for and there are applications that Backbone is really great for and things where you would just use jQuery. So I certainly believe in choosing the right tool for the job.Tom Dale

2. Ember is Opinionated too

After learning your first MVC framework, JavaScript or non JavaScript, this should be kind of a norm for you by now, but I thought this fair warning is still necessary, especially if you are going to build an API mashup app.

Ember.js incorporates common idioms so you can focus on what makes your app special, not reinventing the wheel.

Similar to Angular, while Ember is opinionated, it also tries to make sure that its opinion is just a starting point you can easily change, and that’s the beauty of a well designed extensible framework. And this will be the challenging part of your learning curve as you will find less and less resources that talk about non idiomatic situations.ember_learning_curveAlthough there is a learning curve, it really becomes fun afterwards. Which leads us to the next thing you should know.

3. Active development = outdated help and tutorials

Active development of a framework is actually a good thing, as long as there are no hidden costs associated with it. There is a high probability that for a specific issue that you might search, you will end up on a website or a tutorial that offers a solution which does not fix your problem. You might even stumble up on a nice green checked mark on StackOverflow for an approved answer, and pull your hair on why the same answer that works for everyone does not work for you! My advice will be to just check the article or tutorial published date and referenced code. In most cases the syntax had a very little change, and a little modification will fix your code.ember_betaSimilar to any actively developed framework, Ember guides are not as extensive as they should be, so if you find a solution that does not work in your case, open the API docs and find out how that specific method was implemented. This was not much of an Ember.js case for me than Ember Data. I don’t want to blame anyone here, these are really though programming challenges, and as an open source contributor, I can attest that there will be some edge cases that you will intentionally leave some issues out for those edge case developers in favor of ________ (anything goes.)

4. Use the latest beta for Ember Data until version 1.0

Not all JSON responses conform to Ember’s JSON Convention and formatted like JSON API. And guess what! If you are using Ember Data, you will see variety of code out in the wild. For example without reading this blog post you would not know that there is no need for that revision number anymore.

App.Store = DS.Store.extend({
 // Delete this!
 revision: 13
});

Not only that, in the newer version of Ember Data you don’t even have to initialize DS.Storeanymore. I was using the “latest” keyword in Bower dependency manager settings for my Ember app hoping that I will get the latest stable release, but that was not the case. As much as I know version 0 is never stable, Bower fetched version 0.14 as latest stable release. And problems started from there. I started discovering known and unknown bugs. I started fixing them to realize that the methods that were causing the serialize section to throw errors, in my case, were completely rewritten and factored out in the latest beta releases.stable_vs_betaAs much as Ember data is in it’s beta phase, as long as it works with your app and passes your tests, always use the latest beta till this article is outdated and new stable version of Ember Data is released. I will cover how to configure your Bower setting little further so you wont have any issues, but before that, let’s talk about the obvious thing you should know.

5. Version Control even before writing your first line of code

This is one of the obvious ones, and I don’t even have to mention this, but I have seen this happening a lot, especially with junior developers. It does not matter what version control you use, as long as you allow yourself to move back in history and revert your code if necessary. I am not talking about crazy branching and tagging or… Just keep history of your code, it comes in very handy, even if you are the only developer working on that code.

Springloops Git Repository

At Big Employee we use Springloops commit commands to deploy our code to multiple environments.

Git becomes more fun once you learn to leverage its hidden features. For example at Big Employee we use Springloops as our primary Git repository and Bit Bucket as our secondary repo. Since Git allows you to push to multiple remote repositories with one command, our code is backed up in both places.

git remote add Both ssh://sls@slsapp.com:1234/bigemployee/ember.git
git remote set-url Both --push --add git@bitbucket.org:bigemployee/ember.git
git remote set-url Both --push --add ssh://sls@slsapp.com:1234/bigemployee/ember.git

git remote -v show
git push Both master

6. You will probably rewrite your code, because you know more at the end. Reuse code.

Who cares about forward compatibility when you can move fast and break things, right?

Mark Zuckerberg keynote at Facebook f8 Conference 2014

Mark Zuckerberg keynote at Facebook f8 Conference 2014

At least to some extent, depending to your project, the odds are that you will learn things that you did not know when you started your application. Let’s call that stage a solid working prototype. Therefore, adapt other frameworks and libraries to your workflow to speed up your development. Bootstrap is the most important one here. You can learn it in one evening if not an hour. It is very well documented and it will allow you to work on more mission critical parts of your project. For example the contact section of this website uses a customized version of Bootstrap form and input field styling. #CodeReuse

7. Tools are very important, especially your automation tools… learn them, love them

Automation tools are not just exclusive to Ember. This section could apply to any web application development life cycle.  You’ll be surprised on how productive you become.

I even use them to optimize images and all other things that should not be handled by a human. I don’t want to get into details of why you have to use automation, just consider that it saves time, but I want to talk about the essentials tasks of automation for your Ember app.Grunt Bower NPMWhat I want to talk about is what tools you need and what to be aware of.

Node and npm (Node Package Modules)

It’s true that we are not writing Node.js application but we need some modules that npm will handle for us when we run npm install command. This is what my package.json file looks like: 3 Grunt tasks.

{
  "name": "my-app",
  "description": "my awesome app",
  "version": "0.0.1",
  "private": true,
  "devDependencies": {
    "grunt": "*",
    "grunt-contrib-watch": "*",
    "grunt-ember-templates": "*",
    "grunt-contrib-uglify": "*"
  }
}

Bower

Web apps are made of lots of things — frameworks, libraries, assets, utilities, and Bower will fetch them all for us. Bower requires Node and npm and Git. Here is my my bower.json file. Any time I run Bower, it will find the specified version of libraries I need for my application, like the latest version of jQuery, and keep them nice and organized.

{
    "name": "my-app",
    "version": "1.0.0",
    "dependencies": {
        "jquery": "latest",
        "bootstrap": "latest",
        "d3": "latest",
        "ember": "~1.6",
        "ember-data": "~1.0"
    },
    "authors": [
        "Norik Davtian <norik@bigemployee.com>"
    ],
    "description": "my awesome app",
    "main": "index.html",
    "license": "MIT",
    "private": true,
    "resolutions": {
        "ember": "~1.6"
    }
}

One thing that you might come across when your app has a lot of dependencies is the dependency conflict. Bower will ask you which correct version of that dependency should we install and will allow you to save the resolution to make sure you won’t face the same question later on. For example if we have two jQuery plugins and one needs the latest 2.x version and one requires 1.x version, you will be asked to choose which version of jQuery should be fetched for your application. Make sure you specify the ember data version.

Grunt (The Javascript Task Runner)

Grunt is one of my favorite automation tools. Almost any automation tool that you might think of is written by the community of developers and available as a plugin on Grunt. For example if you want to remove all console logging from your code, which is a very good idea for production code, if you search on Grun plugin site, you will probably find few plugins that will help you do that.

One of the readers mentioned that you might also be interested to check the alternatives to Grunt for your Ember app build and automation such as Ember CLI, Gulp, and Broccoli.

I do not run any pre processors or linting with Grunt as my IDE is configured to do those and highlight it right in the editor, but emberTemplates, uglify, and watch are the tasks I run in this case. Here is how my Gruntfile.js looks like. This should also give you a perspective why I am not using Yeoman. Feel free to fully contact all your files, uglify, and mangle your code. This is my light compression settings here.

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON( 'package.json' ),
    
    emberTemplates: {
      compile: {
        options: {
          templateBasePath: /app\/templates\//
        },
        files: {
          'app/templates.js': 'app/templates/*.hbs'
        }
      }
    },

    watch: {
      emberTemplates: {
        files: 'app/templates/*.hbs',
        tasks: ['emberTemplates']
      },
      js:{
        files: ['app/controllers/*.js',
            'app/routes/*.js',
            'app/models/*.js',
            'app/fixtures.js',
            'app/views/*.js',
            'app/router.js',
            'app/templates.js',
            'app/main.js'],
        tasks: ['uglify']
      }
    },

    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
        mangle: false,
        beautify: true
      },
      build: {
        src: [
//            'libs/jquery/dist/jquery.min.js',
//            'libs/bootstrap/dist/js/bootstrap.min.js', 
//            'libs/handlebars/handlebars.runtime.min.js', 
//            'libs/ember/ember.min.js',
//            'libs/ember-data/ember-data.min.js', 
//            'libs/d3/d3.min.js', 
            'app/main.js', 
            'app/templates.js', 
            'app/models/*.js', 
            'app/controllers/*.js', 
            'app/router.js',
            'app/fixtures.js',
            'app/routes/*.js',
            'app/views/*.js'],
        dest: 'app/app.min.js'
      }
    }
  });
 
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-ember-templates');
  grunt.loadNpmTasks('grunt-contrib-uglify');
 
  // Default task(s).
  grunt.registerTask('default', ['emberTemplates','uglify','watch']);
};

Well Configured IDE (Integrated development environment)

I use NetBeans IDE, just as a personal preference. It does not matter what IDE you use for your development, Eclipse, Sublime Text, or WebStorm, as long as it is configured to maximize your productivity. For example I have linting, CSS pre processors, and even some js minification plugins configured at IDE level.BigEmployee_Norik_s_setupInitially Netbeans was not highlighting handlebar templates properly, but I modified that from Tools > Options > Miscellaneous > Files and added HTML Files (text/html) for hbsfile extension. And now my IDE supports highlighting and formatting for handlebars.

Browser Extensions

Ember Inspector: The most obvious browser extension in this case for our Ember app.
Postman REST Client: Just to test our REST API endpoints without having to write any code. Comes in very handy when we want to get some sample data just to test our code.
And all your other Web Development tools and extensions. 

8. Handlebar runtime, emberTemplates

What is the difference between handlebar.js and handlebar.runtime.js?
Simple answer, performance. More detailed answer, according to handlebars website:

Using the Handlebars precompiler, you can precompile your Handlebars templates to save time on the client and reduce the required runtime size of the handlebars library.

This is where our Grunt task runner will constantly watch our templates, and if there is any change, it will compile our Ember templates into Handlebar compatible runtime JavaScript code.

9. Know JS debugging tools and techniques

This is an entire topic for itself. But I wanted to mention it here because it is in the list of things you should know before starting your next web app using Ember.js and Ember Data or any other library or JavaScript framework. I highly recommend pressing the F12 key on your keyboard more often and start experimenting with it. Especially the Console, that’s where professional JavaScript developers hide their secrets. Knowing how JavaScript objects work will save you a lot of time when working with Ember objects. And finally, I would like to recommend this upcoming book for developers interested to learn more about JavaScript.

Eloquent JavaScript Book, second edition, Written by Marijn Haverbeke

Eloquent JavaScript Book, second edition, Written by Marijn Haverbeke

I hope you enjoyed this lengthy article. Please let me know if I have missed anything, or would like to correct or add anything to this list.