Pytanie Jak wypełnić model szkieletu z wielu adresów URL


Chciałbym użyć pojedynczego modelu szkieletu, który składa się z danych z różnych punktów końcowych adresów URL. Czy możliwe jest określenie wielu adresów URL w ramach jednego modelu? Chciałbym uniknąć ręcznego wywoływania AJAX.

Do tej pory używałem jQuery Deferreds aby wywołać wiele adresów URL i zsyntetyzować ich wyniki w jednym obiekcie.

Mogę wymyślić jak dotąd dwie opcje: zbudowanie modelu szkieletu z modelem częściowym dla każdego adresu URL lub użycie jednego adresu URL, a następnie przesłanianie Model.fetch() aby połączyć się z innymi adresami URL. Ale żaden nie sprawia, że ​​czuję się swobodnie.

(Mogę też spróbować przekupić programistę API, aby udostępnił punkt końcowy połączonego adresu URL ...)


13
2018-01-23 03:52


pochodzenie




Odpowiedzi:


Myślę, że oba zaproponowane sposoby są całkiem rozsądne, ale osobiście zagłosowałbym na fetch podejście.

Używanie modeli zagnieżdżonych ma tę zaletę, że działa "od razu po wyjęciu z pudełka"; innymi słowy, używając jednego modelu dla każdego serwera <=> mapowania klienta, unika się konieczności zmiany dowolnego Backbone.Model metody. Problem z tym podejściem polega na tym, że kończysz z konglomeratem wielu modeli.

Jeśli to ma sens w każdym razie (pobieranie danych na bok), a następnie trzymać się modeli zagnieżdżonych. Ale jeśli nie, to zmuszasz resztę kodu do pracy z kilkoma modelami, zamiast tylko jednym, aby zachować prosty kod pobierania danych. Jeśli wolisz skompresować kod pobierania danych i zachować wszystko inne, to lepiej zastąpić fetch.

fetch robi jedno, a to pobiera dane przez odwzorowanie jeden do jednego między nim a zdalnym adresem URL. Jeśli chcesz jedno-do-wiele mapowanie zamiast tego ma sens, aby zastąpić domyślne fetch zachowanie. Poza tym wiesz, że przesłonięcie jest dość bezpieczne fetch ponieważ nazwa nie jest _fetch, a Backbone używa stylu podkreślenia, aby nazwać jego pseudo-prywatne metody (np. _validate).

Jeśli nadal nie lubisz żadnego z tych podejść, istnieje jeszcze jedna opcja: request wydarzenia. Najnowsza wersja Backbone ma nowe wydarzenie o nazwie request uruchamiany zawsze, gdy fetch jest uruchomiony. Oznacza to, że można skonfigurować program obsługi zdarzeń, który pobiera dane pomocnicze w odpowiedzi na żądanie danych podstawowych, na przykład:

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
});

8
2018-01-23 04:46



Dzięki za edycję GammaGames: the _(this) styl był doskonale wykonalny, ale myślę, że Underscore od tego czasu odszedł, a inne poprawki dla mojej niechlujności również zostały docenione. - machineghost


Istnieje inne rozwiązanie. Aby zastąpić domyślną funkcję Backbone.ajax z zaawansowanym wykonywaniem ajax jquery, która obsługuje tablicę lub hash adresów URL. Będzie ładować dane równolegle i przekazywać kontrolę z powrotem do modelu szkieletu po zakończeniu wszystkich żądań.

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

Teraz modele można ustawić za pomocą tablicy adresów URL, takich jak

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

lub hash adresów URL, np

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

więc gdy parse () zostanie nadpisany, po prostu dodaj podstawową logikę scalania wyników ze wszystkich wywołań ajax, aby przekazać ją do Backbone.Model.parse ().

Po tym wszystkim właściwości z różnych adresów URL będą dostępne w jednym atrybucie modelu.


-1
2018-06-14 01:54