Skip to content

Commit

Permalink
Keep it up-to-date
Browse files Browse the repository at this point in the history
  • Loading branch information
towerhe committed Apr 13, 2014
1 parent e3fd9b0 commit dd5db93
Show file tree
Hide file tree
Showing 25 changed files with 720 additions and 106 deletions.
4 changes: 4 additions & 0 deletions data/guides.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,14 @@
# url: "models/filtering-records"
- title: "使用记录"
url: "models/working-with-records"
- title: "使用Fixture"
url: "models/the-fixture-adapter"
- title: "连接HTTP服务器"
url: "models/connecting-to-an-http-server"
- title: "处理元数据"
url: "models/handling-metadata"
- title: "自定义适配器"
url: "models/customizing-adapters"
- title: "常见问题"
url: "models/frequently-asked-questions"

Expand Down
2 changes: 1 addition & 1 deletion lib/toc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def chapter_github_source_url
if section_slug == guide_slug
return "#{base_guide_url}/#{current_guide['url']}/index.md"
else
return "#{base_guide_url}/#{current_guide['url']}.md"
return "#{base_guide_url}/#{current_guide['url'].gsub(/.html/, '')}.md"
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,29 @@ App.SongsController = Ember.ArrayController.extend({
sortAscending: true // false for descending
});
```

### Item Controller

### 条目控制器

It is often useful to specify a controller to decorate individual items in
the `ArrayController` while iterating over them. This can be done in the
`ArrayController` definition:

在遍历`ArrayController`的条目时,指定一个控制器来装饰单个条目非常有用。这可以在`ArrayController`中进行定义:

```javascript
App.SongsController = Ember.ArrayController.extend({
itemController: 'song'
});
```

or directly in the template:

或者在模板中指定:

```handlebars
{{#each itemController="song"}}
<li>{{name}} by {{artist}}</li>
{{/each}}
```
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ App.ApplicationController = Ember.Controller.extend({
App.SpinButtonComponent = Ember.Component.extend({
classNames: ['button'],
buttonText:"Save",
isLoading:false,
actions:{
isLoading:false,
showLoading:function(){
if(!this.get('isLoading')){
this.set('isLoading', true);
Expand Down Expand Up @@ -94,4 +94,4 @@ Also note that the component does not let multiple clicks get in the way of load

#### 示例

<a class="jsbin-embed" href="http://emberjs.jsbin.com/EXaxEfE/8">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>
<a class="jsbin-embed" href="http://emberjs.jsbin.com/EXaxEfE/14">JS Bin</a><script src="http://static.jsbin.com/js/embed.js"></script>
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,18 @@ Further reading:

更多相关内容:

* <http://emberjs.com/api/classes/Ember.Object.html>
* <http://emberjs.com/api/classes/Ember.Application.html>, See section on "Initializers"
* <http://emberjs.com/api/classes/Ember.Application.html>, 查看"Initializers"部分
* <http://emberjs.com/api/classes/Ember.Application.html#method_inject>
* <http://emberjs.com/guides/templates/conditionals/>
* <http://emberjs.com/guides/templates/writing-helpers/>
* <http://emberjs.com/guides/components/defining-a-component/>
* <http://emberjs.com/api/classes/Ember.ArrayController.html>
* [Ember Object](http://emberjs.com/api/classes/Ember.Object.html)
* [Ember Application Initializers](http://emberjs.com/api/classes/Ember.Application.html#toc_initializers)
* [Method Inject](http://emberjs.com/api/classes/Ember.Application.html#method_inject)
* [Conditionals](http://emberjs.com/guides/templates/conditionals/)
* [Writing Helpers](http://emberjs.com/guides/templates/writing-helpers/)
* [Defining a Component](http://emberjs.com/guides/components/defining-a-component/)
* [Ember Array Controller](http://emberjs.com/api/classes/Ember.ArrayController.html)

* [Ember对象](http://emberjs.com/api/classes/Ember.Object.html)
* [Ember应用初始化](http://emberjs.com/api/classes/Ember.Application.html#toc_initializers)
* [方法注入](http://emberjs.com/api/classes/Ember.Application.html#method_inject)
* [条件表达式](http://emberjs.com/guides/templates/conditionals/)
* [编写助手](http://emberjs.com/guides/templates/writing-helpers/)
* [定义组件](http://emberjs.com/guides/components/defining-a-component/)
* [Ember数组控制器](http://emberjs.com/api/classes/Ember.ArrayController.html)
202 changes: 202 additions & 0 deletions source/bilingual_guides/models/customizing-adapters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
In Ember Data, the logic for communicating with a backend data store
lives in the `Adapter`. Ember Data's Adapter has some built-in
assumptions of how a [REST API](http://jsonapi.org/) should look. If
your backend conventions differ from these assumptions Ember Data
makes it easy to change its functionality by swapping out or extending
the default Adapter.

在Ember Data中,处理与后台数据仓库通信的逻辑是通过`Adapter`来完成的。Ember Data适配器内置了一些关于[REST API](http://jsonapi.org)的假定。如果后台的实现与Ember Data假定的惯例不同,那么通过扩展缺省的适配器可能很容易的实现。

Some reasons for customizing an Adapter include using
`underscores_case` in your urls, using a medium other than REST to
communicate with your backend API or even using a
[local backend](https://github.com/rpflorence/ember-localstorage-adapter).

有时因为一些原因需要自定义适配器,例如需要使用下划线风格的URL,使用REST外的其他媒介来与后台通信,或者是使用[本地后台](https://github.com/rpflorence/ember-localstorage-adapter).

Extending Adapters is a natural process in Ember Data. Ember takes the
position that you should extend an adapter to add different
functionality instead of adding a flag. This results in code that is
more testable, easier to understand and reduces bloat for people who
may want to subclass your adapter.

扩展适配器在Ember Data中是一个常见的过程。Ember的立场是应该通过扩展适配器来添加不同的功能,而非添加标识。这样可以使得代码更加容易测试,更加易于理解,同时也降低了可能需要扩展适配器的用户的代码。

If your backend has some consistent rules you can define an
`ApplicationAdapter`. The `ApplicationAdapter` will get priority over
the default Adapter, however it will still be superseded by model
specific Adapters.

如果后台具有一定的一致性规则,那么可以定义一个`ApplicationAdapter``ApplicationAdapter`的优先级比缺省的适配器高,但是又会被模型特定的适配器取代。

```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
// Application specific overrides go here
});
```

If you have one model that has exceptional rules for communicating
with its backend than the others you can create a Model specific
Adapter by naming an adapter "ModelName" + "Adapter".

如果一个模型的后台有一些特殊的规则,那么可以定义一个模型特定的适配器,并将适配器命名为:"ModelName" + "Adapter"。

```js
App.PostAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1'
});
```

By default Ember Data comes with several builtin adapters. Feel free
to use these adapters as a starting point for creating your own custom
adapter.

缺省情况下,Ember Data内置了一些非常有用的适配器。可以根据自己的实际情况,选择其中之一作为起点来自定义适配器。

- [DS.Adapter](/api/data/classes/DS.Adapter.html) is the basic adapter
with no functionality. It is generally a good starting point if you
want to create an adapter that is radically different from the other
Ember adapters.

- [DS.Adapter](/api/data/classes/DS.Adapter.html)是最基础的适配器,其自身不包含任何功能。如果需要创建一个与Ember适配器有根本性区别的适配器,那么可以这里入手。

- [DS.FixtureAdapter](/api/data/classes/DS.FixtureAdapter.html) is an
adapter that loads records from memory. Its primarily used for
development and testing.

- [DS.FixtureAdapter](/api/data/classes/DS.FixtureAdapter.html)是一个用来从内存中加载记录的适配器,常用于开发和测试阶段。

- [DS.RESTAdapter](/api/data/classes/DS.RESTAdapter.html) is the most
commonly extended adapter. The `RESTAdapter` allows your store to
communicate with an HTTP server by transmitting JSON via XHR. Most
Ember.js apps that consume a JSON API should use the REST adapter.

- [DS.RESTAdapter](/api/data/classes/DS.RESTAdapter.html)是最通用的扩展适配器。`RESTAdapter`可以实现`store`与HTTP服务器之间通过XHR交互JSON数据。大部分使用JSON
API的Ember应用都应该使用`RESTAdapter`

- [DS.ActiveModelAdapter](/api/data/classes/DS.ActiveModelAdapter.html)
is a specialized version of the `RESTAdapter` that is set up to work
out of the box with Rails-style REST APIs.

- [DS.ActiveModelAdapter](/api/data/classes/DS.ActiveModelAdapter.html)是一个`RESTAdapter`的特列,用于与Rails风格的REST API协同工作。


## Customizing the RESTAdapter

## 自定义RESTAdapter

The [DS.RESTAdapter](/api/data/classes/DS.RESTAdapter.html) is the
most commonly extended adapter that ships with Ember Data. It has a
handful of hooks that are commonly used to extend it to work with
non-standard backends.

[DS.RESTAdapter](/api/data/classes/DS.RESTAdapter.html)是Ember
Data提供的一个最通用的扩展适配器。它提供了一些非常有用的,可以扩展来与非标准化的后台接口通信的钩子。

#### Endpoint Path Customization

#### 自定义端点路径

The `namespace` property can be used to prefix requests with a
specific url namespace.

`namespace`属性用来指定一个特定的url前缀。

```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/1'
});
```

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

`App.Person`的请求将会发至`/api/1/people/1`


#### Host Customization

#### 自定义主机

By default the adapter will target the current domain. If you would
like to specify a new domain you can do so by setting the `host`
property on the adapter.

缺省情况下,适配器认为主机是当前域。如果希望指定一个新的域,那么可以通过设置适配器的`host`属性来指定。

```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'https://api.example.com'
});
```

Requests for `App.Person` would now target `https://api.example.com/people/1`.

`App.Person`的请求将会发至`https://api.example.com/people/1`

#### Path Customization

#### 自定义路径

By default the `RESTAdapter` will attempt to pluralize and camelCase
the model name to generate the path name. If this convention does not
conform to your backend you can override the `pathForType` method.

缺省情况下,`RESTAdapter`尝试将模型名进行驼峰化和复数化来作为路径名。如果这种惯例并不符合使用的后台接口,可以通过重载`pathForType`方法来实现。

For example, if you did not want to pluralize model names and needed
underscore_case instead of camelCase you could override the
`pathForType` method like this:

例如,并不需要将模型名称复数化,需要采用下划线分割的模式替代驼峰命名,那么可以这样来重载`pathForType`方法:

```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
return Ember.String.underscore(type);
}
});
```

Requests for `App.Person` would now target `/person/1`.
Requests for `App.UserProfile` would now target `/user_profile/1`.

`App.Person`的请求将会发至`/person/1`
`App.UserProfile`的请求将会发至`/user_profile/1`

#### Authoring Adapters

#### 创作适配器

The `defaultSerializer` property can be used to specify the serializer
that will be used by this adapter. This is only used when an model
specific serializer or ApplicationSerializer are not defined.

`defaultSerializer`属性可以用来指定适配器使用的序列化对象。这只在没有模型特定的序列化对象,也没有`ApplicationSerializer`的情况下。

In an application, it is often easier to specify an
`ApplicationSerializer`. However, if you are the author of a community
adapter it is important to remember to set this property to ensure
Ember does the right thing in the case a user of your adapter
does not specify an `ApplicationSerializer`.

在一个应用中,指定一个`ApplicationSerializer`比较容易。但是如果自定了一个通信的适配器,并且没有指定一个`ApplicationSerializer`,那么设定`defaultSerializer`属性,来确保Ember的行为正确性比较重要。

```js
MyCustomAdapterAdapter = DS.RESTAdapter.extend({
defaultSerializer: '-default'
});
```


## Community Adapters

## 社区适配器

If none of the builtin Ember Data Adapters work for your backend,
be sure to check out some of the community maintained Ember Data
Adapters. Some good places to look for Ember Data Adapters include:

如果Ember Data内置的适配器并不能很好的与使用的后台工作,可以查看社区维护的Ember Data适配器,看有不有合适的选择。可以去一下地方去查找:

- [GitHub](https://github.com/search?q=ember+data+adapter&ref=cmdform)
- [Bower](http://bower.io/search/?q=ember-data-)
86 changes: 86 additions & 0 deletions source/bilingual_guides/models/frequently-asked-questions.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,89 @@ App.PostsFavoritedRoute = Ember.Route.extend({
}
});
```

#### How do I inform Ember Data about new records created on the backend?

#### 如何将后台创建的记录通知Ember Data

When you request a record using Ember Data's `store.find` method, Ember
will automatically load the data into the store. This allows Ember to
avoid the latency of making a round trip to the backend next time
that record is requested. Additionally, loading a record into the
store will update any `RecordArray`s (e.g. the result of
`store.filter` or `store.all`) that should include that record. This
means any data bindings or computed properties that depend on the
`RecordArray` will automatically be synced to include the new or
updated record values.

当通过Ember
Data的`store.find`方法来请求一条记录时,Ember会自动将数据加载到`store`中。这样Ember就避免了在之后在发起一个请求来获取已经获取到的记录。此外,加载一条记录到`store`时,所有的包含该条记录的`RecordArray`都会被更新(例如`store.filter`或者`store.all`构造的)。这就意味着所有依赖与`RecordArray`的数据绑定或者计算属性都会在添加新的或者更新记录值的时候自动进行同步。

Some applications may want to add or update records in the store
without requesting the record via `store.find`. To accomplish this you
can use the `DS.Store`'s `push`, `pushPayload`, or `update`
methods. This is useful for web applications that have a channel
(such as [SSE](http://dev.w3.org/html5/eventsource/) or
[Web Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)) to
notify it of new or updated records on the backend.

而一些应用可能希望能不通过`store.find`请求记录来添加或者更新`store`中得记录。为了实现这种需求,可以通过使用`DS.Store``push``pushPayload`,或者`update`方法。这对于那些有一个通道(例如[SSE](http://dev.w3.org/html5/eventsource/)或者[Web Socket](http://www.w3.org/TR/2009/WD-websockets-20091222/))通知应用后台有新记录创建或者更新非常有用。

[push](http://emberjs.com/api/data/classes/DS.Store.html#method_push)
is the simplest way to load records to Ember Data's store. When using
`push` it is important to remember to deserialize the JSON object
before pushing it into the store. `push` only accepts one record at a
time. If you would like to load an array of records to the store you
can call
[pushMany](http://emberjs.com/api/data/classes/DS.Store.html#method_pushMany).

[push](http://emberjs.com/api/data/classes/DS.Store.html#method_push)是加载记录到Ember
Data的`store`的最简单方法。当使用`push`时,一定要记住将JSON对象推入`store`之前将其反序列化。`push`一次只接受一条记录。如果希望一次加载一组记录到`store`那么可以调用[pushMany](http://emberjs.com/api/data/classes/DS.Store.html#method_pushMany).

```js
socket.on('message', function (message) {
var type = store.modelFor(message.model);
var serializer = store.serializerFor(type.typeKey);
var record = serializer.extractSingle(store, type, message.data);
store.push(message.model, record);
});
```

[pushPayload](http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload)
is a convenience wrapper for `store#push` that will deserialize
payloads if the model's Serializer implements a `pushPayload`
method. It is important to note this method will not work with the
`JSONSerializer` because it does not implement a `pushPayload`
method.

[pushPayload](http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload)是一个`store#push`方法的便利封装,它将使用模型实现了`pushPayload`方法的序列化对象来反序列化有效载荷。需要注意的是这个方法并不能与`JSONSerializer`一同使用,因为其并没有实现`pushPayload`方法。

```js
socket.on('message', function (message) {
store.pushPayload(message.model, message.data);
});
```

[update](http://emberjs.com/api/data/classes/DS.Store.html#method_update)
works likea `push` except it can handle partial attributes without
overwriting the existing record properties. This method is useful if
your web application only receives notifications of the changed
attributes on a model. Like `push` it is important to remember to
deserialize the JSON object before calling `update`.

[update](http://emberjs.com/api/data/classes/DS.Store.html#method_update)`push`方法类似,不同的是其可以处理部分属性,而不需要覆盖整个记录的属性。这个方法对于只接收到记录改变的属性的通知的应用尤为有用。与`push`方法一样,`update`需要在调用之前将JSON对象反序列化。

```js
socket.on('message', function (message) {
var hash = message.data;
var type = store.modelFor(message.model);
var fields = Ember.get(type, 'fields');
fields.forEach(function(field) {
var payloadField = Ember.String.underscore(field);
if (field === payloadField) { return; }
hash[field] = hash[payloadField];
delete hash[payloadField];
});
store.push(message.model, hash);
});
```
Loading

0 comments on commit dd5db93

Please sign in to comment.