Подтвердить что ты не робот

Как заполнить модель Backbone из нескольких URL-адресов

Я хотел бы использовать одну модель Backbone, которая состоит из данных из разных конечных точек URL. Можно ли указать несколько URL-адресов в рамках одной модели? Я хотел бы избежать вызова AJAX вручную.

До сих пор я использовал jQuery Deferreds для вызова нескольких URL-адресов и синтеза их результатов в один объект.

Я могу представить два варианта: построение модели Backbone с частичной моделью для каждого URL-адреса или использование одного URL-адреса, а затем переопределение Model.fetch() для вызова других URL-адресов. Но никто не делает меня удобным.

(Или я могу попытаться подкупить разработчика API, чтобы предоставить объединенную конечную точку URL...)

4b9b3361

Ответ 1

Я думаю, что оба способа, которые вы предложили, вполне разумны, но лично я проголосовал за подход fetch.

Использование вложенных моделей имеет то преимущество, что работает "из коробки"; другими словами, используя одну модель для каждого сопоставления клиента <= > , вы избегаете изменять любые методы Backbone.Model. Проблема с этим подходом заключается в том, что вы завершаете конгломерацию нескольких моделей.

Если это имеет смысл в любом случае (извлечение данных в сторону), то придерживайтесь вложенных моделей. Но если нет, вы вынуждаете остальную часть кода работать с несколькими моделями, а не только с целью сохранить код поиска данных простым. Если вы хотите просто усложнить код поиска данных и сохранить все остальное просто, вам лучше переписать fetch.

fetch делает одно, и это извлекает данные через взаимно однозначное сопоставление между ним и удаленным URL. Если вам требуется сопоставление one-to- many, то имеет смысл просто переопределить поведение по умолчанию fetch. Кроме того, вы знаете, что достаточно безопасно переопределять fetch, потому что это имя не _fetch, а Backbone использует стиль подчеркивания, чтобы назвать его псевдо-частными методами (например, _validate).

Если вам все еще не нравится любой из этих подходов, есть еще один вариант: request события. В последней версии Backbone появилось новое событие request, которое запускается всякий раз, когда запускается fetch. Это означает, что вы можете настроить обработчик событий, который извлекает ваши вторичные данные в ответ на первичный запрос данных, например:

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

Ответ 2

Существует другое решение. Чтобы переопределить функцию Backbone.ajax по умолчанию с расширенным выполнением jQuery ajax, поддерживающим массив или хэш URL-адресов. Он будет загружать данные параллельно и передавать управление обратно в базовую модель после завершения всех запросов.

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]

или хеш URL-адресов, например

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-адресов будут доступны в одном атрибуте модели.