访问传递在JSON服务器响应中的元信息

23
我正在使用Ember-Data Rest-Adapter,从服务器返回的JSON基本上看起来像Active Model Serializers Documentation中的JSON。请注意,保留HTML标签,不进行解释。
{
  "meta": { "total": 10 },
  "posts": [
    { "title": "Post 1", "body": "Hello!" },
    { "title": "Post 2", "body": "Goodbye!" }
  ]
}

从服务器获取数据是有效的,但不幸的是我无法找出在哪里可以访问我的JSON响应中的元信息。

根据我在ember-data的github问题中的研究,支持元信息似乎已经 实现,使用提交1787bff

但即使有测试用例,我也无法弄清楚如何访问元信息。

App.PostController = Ember.ArrayController.extend({
   ....
   requestSearchData: function(searchParams){
      posts = App.Post.find(searchParams);
      this.set('content', posts);
      // don't know how to access meta["total"]
      // but I want to do something like this:
      // this.set('totalCount', meta["total"])
   }
})

请问有人能为我解答一下吗?我知道Ember API正在快速更新,但我相信我只是遗漏了一个小部分,这实际上是可能的。

3个回答

7
我发现了一种更加简洁的方法,可以从ember-data的服务器响应中提取元信息。
我们需要告诉序列化器期望哪些元信息(在这个例子中是分页信息):
 App.serializer = DS.RESTSerializer.create();

 App.serializer.configure({ pagination: 'pagination' });

 App.CustomAdapter = DS.RESTAdapter.extend({
   serializer: App.serializer
 });

 App.Store = DS.Store.extend({
   adapter: 'App.CustomAdapter'
 });

之后,每当服务器发送一个带有分页对象的元属性时,该对象将被添加到所请求的模型类的存储的属性中。

例如,使用以下响应:

  {
    'meta': {'pagination': { 'page': 1, 'total': 10 } },
    'posts':[
      ...
    ]
  }

App.Post-Model的TypeMap将在帖子加载后包括分页对象。

您无法直接观察存储的TypeMaps属性,因此我在PostsController中添加了一个计算属性,以便访问请求的分页元信息:

 App.PostsController = Ember.ArrayController.extend({
    pagination: function () {
      if (this.get('model.isLoaded')) {
        modelType = this.get('model.type');
        this.get('store').typeMapFor(modelType).metadata.pagination
      }
    }.property('model.isLoaded')
 });

我真的不认为这是元信息问题的好解决方案,但这是我在使用Ember-Data时能想到的最好解决方案。也许将来会更容易。


我发现的一个问题是,如果元数据值未从服务器返回或为空字符串,则Ember将保留旧值。我不得不采取返回诸如“none”之类的字符串而不是空值的方法。 - Kevin Ansfield

6

我找到了一种访问响应中传递的元信息的方法。但不幸的是,似乎ember-data不支持它,并且我正在将元信息写入全局变量,然后通过请求控制器中的绑定访问它。

最终,我对RESTAdapter使用的序列化器进行了定制:

App.CustomRESTSerializer = DS.RESTSerializer.extend({
  extractMeta: function(loader, type, json) {
    var meta;
    meta = json[this.configOption(type, 'meta')];
    if (!meta) { return; }
    Ember.set('App.metaDataForLastRequest', meta);
    this._super(loader, type, json);
  }
});

App.Store = DS.Store.extend({
  revision: 11,
  adapter: DS.RESTAdapter.create({
    bulkCommit: false,
    serializer: App.CustomRESTSerializer
  })
});

我知道这并不是特别优美,实际上我认为这违背了ember-data期望我们做的事情,但目前它可以正常工作。

我会尝试以更好的方式使其与ember-data配合,并在其可用时提交一个pull request或在github上开启问题,以便其他人也能使用。

如果有人找到更干净的解决方案,请告诉我。


嗨,迈克尔,你是如何通过请求控制器中的绑定访问全局变量的?如果我想要在我的ApplicationController中访问App.metaDataForLastRequest.current_user,我应该做些什么呢?类似这样:currentUserBinding: 'App.metaDataForLastRequest.current_user' ,然后从控制器和视图中使用currentUser变量吗?感谢你能给予的任何帮助,或者如果你已经找到了更好的方法! - Jack Johnson
1
我将之前的评论发布为一个问题:https://dev59.com/wnHYa4cB1Zd3GeqPHRM7。任何帮助都将不胜感激! - Jack Johnson

2

我认为您可以立即解决问题的方法是将totalCount附加到您的模型(recordArray)上,参见此线程

另一种方法是创建自己的适配器:

DS.Adapter.create({
  find: function (store, type, id) {
    $.ajax({
      url:      type.url,
      dataType: 'jsonp',
      context:  store,
      success:  function(response){
        this.load(type, id, response.data);
      }
    });
  },
  findAll: function(store, type) {
    $.ajax({
      url:      type.url,
      dataType: 'jsonp',
      context:  store,
      success:  function(response){
        this.loadMany(type, response.data);
      }
    });
  }
});

在findAll方法的成功回调中,响应参数应该是一个你需要的对象:

response: {
  meta: {
    totalCount: 10
  },
  posts: [{}, {}]
}

希望这能帮到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接