如何从多个URL填充Backbone模型

时间:2013-01-23 03:52:44

标签: ajax backbone.js

我想使用由来自不同URL端点的数据组成的单个Backbone模型。是否可以在单个模型中指定多个URL?我想避免手动调用AJAX。

到目前为止,我一直在使用jQuery Deferreds来调用多个网址并将其结果合成为一个对象。

到目前为止,我可以考虑两个选项:构建一个Backbone模型,其中包含每个URL的部分模型,或者使用一个URL,然后覆盖Model.fetch()来调用其他URL。但是没有人能让我感到舒服。

(或者我可以尝试贿赂API开发人员以提供合并的URL端点...)

2 个答案:

答案 0 :(得分:8)

我认为你提出的两种方式都很合理,但我个人对fetch方法投了赞成票。

使用嵌套模型具有“开箱即用”的优点;换句话说,通过为每个服务器使用一个模型< =>客户端映射您无需更改任何Backbone.Model方法。然而,这种方法的问题在于你结束了多个模型的集合。

如果这有意义(除了数据检索),那么坚持使用嵌套模型。但是如果不是这样,你就会强迫你的其余代码使用多个模型而不仅仅是一个模型,以保证数据检索代码的简单性。如果您只是简单地复制数据检索代码并保持其他一切简单,那么最好覆盖fetch

fetch做了一件事,那就是通过它与远程URL之间的一对一映射来检索数据。如果您想要一对一映射,那么仅覆盖默认的fetch行为就非常有意义了。另外,您知道覆盖fetch是合理安全的,因为它的名称不是_fetch,而Backbone使用下划线样式来命名它的伪私有方法(例如。_validate)。 / p>

如果您仍然不喜欢这两种方法,还有另外一种选择:request个事件。最新版本的Backbone有一个名为request的新事件,只要fetch启动就会触发。这意味着您可以设置一个事件处理程序来检索辅助数据以响应主数据的请求,如下所示:

Backbone.Model.extend({
    initialize: function() {
        this.on('request', this.handleRequest);
        _.bindAll(this, 'handleTriggeredResponse');
    },
    handleRequest: function() {
        $.ajax({url: secondDataUrl, complete: this.handleTriggeredResponse});
        $.ajax({url: tertiaryDataUrl, complete: this.handleTriggeredResponse});
    },
    handleTriggeredResponse: function(response) {
        this.set(response.data);
    },
    url: firstDataUrl
});

答案 1 :(得分:-1)

还有另一种解决方案。使用支持url的数组或散列的高级jquery ajax执行来覆盖默认的Backbone.ajax函数。它将并行加载数据,并在所有请求完成后将控制权传递回Backbone模型。

ajaxForArray = ->
  options = _.first arguments
  $.when.apply $, options.url.map (url) ->
    $.ajax _.merge _.omit(options, ['url', 'success']), {url}
  .done ->
    resp =
      if options.url.length > 1
        _.slice(arguments).map (arg) -> _.first arg
      else
        _.first arguments
    options.success? resp

ajaxForHash = ->
  options = _.first arguments
  pairs = _.transform options.url, (memo, url, key) ->
    memo.push {key, url}
  , []
  $.when.apply $, pairs.map (pair) ->
    $.ajax _.merge _.omit(options, ['url', 'success']), url: pair.url
  .done ->
    resp = _.slice(arguments).reduce (memo, arg, i) ->
      memo[pairs[i].key] = _.first arg
      memo
    , {}
    options.success? resp

Backbone.ajax = ->
  options = _.first arguments
  if _.isArray options.url
    ajaxForArray.apply $, arguments
  else if _.isObject(options.url) and not _.isFunction options.url
    ajaxForHash.apply $, arguments
  else
    $.ajax.apply $, arguments

现在可以使用网址数组设置模型,例如

class ArrayBasedModel extends Backbone.Model
  url: ['/aoo', '/boo', '/coo']
  parse: (resp) ->
    super _.extend {}, resp[0], resp[1], resp[2]

或网址的哈希,例如

class HashBasedModel extends Backbone.Model
  url: {aoo: '/aoo', boo: '/boo', coo: '/coo'}
  parse: (resp) ->
    super _.extend {}, resp.aoo, resp.boo, resp.coo

所以当重写parse()时,只需添加一些合并来自所有ajax调用的结果的基本逻辑,将其传递给Backbone.Model.parse()。

在所有这些之后,来自不同URL的属性将在一个模型属性中可用。