13

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

到目前为止,我一直在使用jQuery Deferreds来调用多个 URL 并将它们的结果合成到一个对象中。

到目前为止,我可以想到两种选择:为每个 URL 构建一个带有部分模型的 Backbone 模型,或者使用一个 URL 然后覆盖Model.fetch()调用其他 URL。但没有一个让我感到舒服。

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

4

2 回答 2

8

我认为您建议的两种方式都非常合理,但我个人会投票赞成这种fetch方法。

使用嵌套模型具有“开箱即用”的优势;换句话说,通过为每个服务器 <=> 客户端映射使用一个模型,您可以避免更改任何Backbone.Model方法。但是,这种方法的问题在于您最终会得到多个模型的组合。

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

fetch做一件事,那就是通过数据与远程 URL 之间的一对一映射来检索数据。如果您想要一个一对多fetch的映射,那么只需覆盖默认行为就非常有意义。另外,您知道重写它是相当安全的,fetch因为它的名称 is not _fetch,并且 Backbone 使用下划线样式将其命名为伪私有方法(例如。_validate)。

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

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
});
于 2013-01-23T04:46:38.663 回答
-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

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

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 的属性将在一个模型属性中可用。

于 2016-06-14T01:54:03.193 回答