如何为ember.js创建自定义适配器?

时间:2013-07-30 04:25:26

标签: javascript ajax rest ember.js

我打算使用ember.js,但是我的REST api与打包的REST适配器并不完全一致。我想“覆盖”查找并能够将自己的ajax放入其中。我不喜欢一个余烬findAll如何检索我的所有文件没有分页选项,所以与其他查询参数一起使用会很有用 - 这就是我想编写自己的ajax的原因。我一直无法找到关于如何做到这一点的任何文档。

3 个答案:

答案 0 :(得分:62)

对于Ember数据

这是Ember Data 1.0 beta 9的最新版本。

扩展其中一个Ember数据适配器。使其在网站范围内:

App.ApplicationAdapter = DS.RESTAdapter.extend(....

使其具体模型:

App.FooAdapter = DS.RESTAdapter.extend(...

然后,您将定义要覆盖的实现。您始终可以选择调用this._super并恢复到基本实现。 e.g。

App.NotesAdapter = DS.RESTAdapter.extend({
  find: function(store, type, id) {
    id = "foo" + id;
    return this._super(store, type, id);
  }
});

或者你可以完全覆盖实现:

App.NotesAdapter = DS.RESTAdapter.extend({
  find: function(store, type, id) {
    // Do your thing here
    return this.ajax(this.buildURL(type.typeKey, id), 'GET');
  },

  findAll: function(store, type, sinceToken) {
    // Do your thing here
    var query;

    if (sinceToken) {
      query = { since: sinceToken };
    }

    return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
  },

  findQuery: function(store, type, query) {
    // Do your thing here
    return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
  },

  findMany: function(store, type, ids, owner) {
    return this.ajax(this.buildURL(type.typeKey), 'GET', { data: { ids: ids } });
  },
   .....
});

要查看完整的API,您可以覆盖:http://emberjs.com/api/data/classes/DS.RESTAdapter.html

串行

通常更重要的是滚动自己的序列化程序来按摩数据以适应您的休息端点。以下是转换文档https://github.com/emberjs/data/blob/master/TRANSITION.md中的一些有用信息。

简短版本是,一旦完成Ajax请求,生成的有效负载将通过以下挂钩发送:

  1. 如果原始请求是针对单个记录(如find / save),则将有效负载发送到extractSingle;如果原始请求针对记录数组(如findAll / findQuery),则将有效负载发送到extractArray
  2. 这些方法的默认行为是将有效负载的顶层拆分为多个较小的记录。
  3. 每个较小的记录都会被发送到规范化,这可以一次对记录进行规范化。
  4. 最后,特定类型的记录可以特别规范化。
  5.     App.PostSerializer = DS.RESTSerializer.extend({
          extractSingle: function(store, type, payload, id) {
            // massage
            this._super(store, type, payload, id);
          },
          extractArray: function(store, type, payload) {
            // massage
            this._super(store, type, payload);
          },
          normalize: function(type, hash, property) {
            // massage
            this._super(type, hash, property);
          }
        });
    
    • 当有效负载的顶层组织方式与Ember Data预期不同时,使用extractSingle和extractArray
    • 如果有效负载中的所有子哈希都可以以相同的方式进行规范化,则使用no​​rmalize来规范化子哈希。
    • 使用normalizeHash来规范化特定的子哈希值。
    • 如果你覆盖extractSingle,extractArray或规范化,请确保调用super,以便调用链的其余部分。

    滚动你自己的

    App.FooAdapter = Ember.Object.extend({
      find: function(id){
        return $.getJSON('http://www.foolandia.com/foooo/' + id);
      }
    });
    

    然后从您的路线或任何地方

    App.FooRoute = Ember.Route.extend({
      model: function(){
        var adapter = App.FooAdapter.create();
        return adapter.find(1);
      }
    });
    

    现在我亲自将接头注入路线只是为了让我的生活更轻松:

    App.initializer({
        name: "fooAdapter",
    
        initialize: function (container, application) {
            application.register("my:manager", application.FooAdapter);
            application.inject("controller", "fooAdapter", "my:manager");
            application.inject("route", "fooAdapter", "my:manager");
        }
    });
    

    然后在路线上你会变得懒散而且:

    App.FooRoute = Ember.Route.extend({
      model: function(){
        return this.fooAdapter.find(1);
      }
    });
    

    示例:http://emberjs.jsbin.com/OxIDiVU/676/edit

    您可以在不使用Ember数据的情况下阅读有关Ember的更多信息:Ember without Ember Data

答案 1 :(得分:7)

我遇到了同样的问题。我也想用我的后端(cakePHP)稍微不同的格式,并且无法弄清楚如何做到这一点。之前的答案很棒,但您可能不需要重新定义每个方法,只需通过覆盖RESTAdapter中的buildURL来更改URL的格式。

例如,我想使用cakePHP的扩展名,并希望我的网址看起来如此,应用程序范围:

  • /users.json(findAll)
  • /users/view/1.json(find)
  • /users/delete/1.json
  • /users/edit.json(POST)
  • /users/add.json(POST)

经过多次拔毛并认识到余烬数据是必不可少的,我使用了以下代码:

App.ApplicationAdapter = DS.RESTAdapter.extend({
  buildURL: function(type, id) {
    var url = '/' + this.pluralize(type.typeKey);

    if (id) {
        url += '/' + id;
    }

    url += '.json';

    return url;
  }
});

Ember的文档很好,但他们的大多数示例都使用FIXTURE数据。我希望他们有一个简单的例子,说明如何针对不同情况编写不同类型的适配器。

答案 2 :(得分:1)

对于自己编码适配器的用户,如果需要从适配器返回值(例如userId),则可以返回json或promise。这是返回承诺的例子:

App.RequestAdapter = Ember.Object.extend({
    newRequest: function (data) {
        return new Ember.RSVP.Promise(function (resolve, reject) {
            Ember.$.ajax({
                type: 'POST',  // method post
                url: '/Request/Create', //target url
                data: JSON.stringify(data), //the JSON.stringify converts data to JSON
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                success: function (response) {
                    resolve(response);
                },
                error: function (reason) {
                    reject(reason);
                }
            });
        });
    }
});

//use this adapter in  your controller
var adapter = App.RequestAdapter.create();

adapter.newRequest(data).then(function (response) {   //newRequest is method of our adapter
    console.log(response.userId);  //specify response data
}, function(error){
    //handle error  
});

您可以在此处获取有关Ember承诺的更多信息:https://hackhands.com/3-ways-ember-js-leverages-promises/或此处http://emberjs.com/api/classes/RSVP.Promise.html