EmberJS: jak załadować wiele modeli na tej samej trasie?

Chociaż nie jestem nowy w tworzeniu stron internetowych, jestem całkiem nowy w frameworkach MVC po stronie klienta. Poszperałem trochę i postanowiłem spróbować z Emberjsem. Przejrzałem Przewodnik TodoMVC i to miało dla mnie sens...

Mam skonfigurować bardzo podstawową aplikację; trasa indeks, dwa modele i jeden szablon. Mam uruchomiony skrypt php po stronie serwera, który zwraca kilka wierszy db.

Jedna rzecz, która mnie bardzo myli, to sposób ładowania wielu modeli na tej samej trasie. Przeczytałem kilka informacji o używaniu setupController, ale nadal jestem niejasny. W moim szablonie mam dwie tabele, które próbuję załadować niepowiązanymi wierszami db. W bardziej tradycyjnej aplikacji internetowej po prostu wydałbym instrukcje sql i zapętliłbym je, aby wypełnić wiersze. Mam trudności z tłumaczeniem tego pojęcia na EmberJS.

Jak załadować wiele modeli niepowiązanych danych na tej samej trasie?

Używam najnowszych bibliotek danych Ember I Ember.

Update

Chociaż pierwsza odpowiedź podaje metodę obsługi, druga odpowiedź wyjaśnia, Kiedy jest odpowiednia, a różne metody, kiedy nie jest odpowiednia.

Author: Kingpin2k, 2013-12-11

5 answers

Możesz użyć Ember.RSVP.hash do załadowania kilku modeli:

app/routes/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    return Ember.RSVP.hash({
      people: this.store.findAll('person'),
      companies: this.store.findAll('company')
    });
  },

  setupController(controller, model) {
    this._super(...arguments);
    Ember.set(controller, 'people', model.people);
    Ember.set(controller, 'companies', model.companies);
  }
});

A w szablonie możesz odwołać się do people i companies Aby pobrać załadowane dane:

app/templates/index.js

<h2>People:</h2>
<ul>
  {{#each people as |person|}}
    <li>{{person.name}}</li>
  {{/each}}
</ul>
<h2>Companies:</h2>
<ul>
  {{#each companies as |company|}}
    <li>{{company.name}}</li>
  {{/each}}
</ul>

To jest Twistdle z tą próbką: https://ember-twiddle.com/c88ce3440ab6201b8d58

 92
Author: Marcio Junior,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-14 22:33:41

Uwaga:

Chcesz być ostrożny, czy zwracanie wielu modeli w hooku modelu jest odpowiednie. Zadaj sobie to proste pytanie:

  1. czy Moja trasa ładuje dynamiczne dane na podstawie adresu url za pomocą slug :id? tj. this.resource('foo', {path: ':id'});

Jeśli odpowiedziałeś tak

Nie próbuj ładować wielu modeli z haka modelu na tej trasie!!! powodem jest sposób, w jaki Ember obsługuje połączenia z trasami. Jeśli podasz model podczas łączenia się z tą trasą ({{link-to 'foo' model}}, transitionTo('foo', model)) pominie hak modelu i użyje dostarczonego modelu. Jest to prawdopodobnie problematyczne, ponieważ oczekiwano wielu modeli, ale tylko jeden model zostanie dostarczony. Oto alternatywa:

Zrób to w setupController/afterModel

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('model2', {bird:'is the word'});
  }
});

Przykład: http://emberjs.jsbin.com/cibujahuju/1/edit

Jeśli potrzebujesz go, aby zablokować przejście (tak jak robi to hook modelu), zwróć obietnicę z afterModel hook. Będziesz musiał ręcznie zachować śledź wyniki z tego haka i podłącz je do kontrolera.

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  afterModel: function(){
    var self = this;
    return $.getJSON('/authors').then(function(result){
      self.set('authors', result);
    });
  }, 
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('authors', this.get('authors'));
  }
});

Przykład: http://emberjs.jsbin.com/diqotehomu/1/edit

Jeśli odpowiedziałeś Nie

Śmiało, zwróćmy wiele modeli z haka modelu trasy:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return {
           model1: ['red', 'yellow', 'blue'],
           model2: ['green', 'purple', 'white']
    };
  }
});

Przykład: http://emberjs.jsbin.com/tuvozuwa/1/edit

Jeśli jest to coś, na co trzeba czekać (np. połączenie z serwerem, jakaś obietnica)]}
App.IndexRoute = Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
           model1: promise1,
           model2: promise2
    });
  }
});

Przykład: http://emberjs.jsbin.com/xucepamezu/1/edit

W przypadku danych Ember

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: store.find('dog')
    });
  }
});

Przykład: http://emberjs.jsbin.com/pekohijaku/1/edit

Jeśli jedna jest obietnicą, a druga nie, to wszystko jest dobre, RSVP chętnie użyje tej wartości]}
App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: ['pluto', 'mickey']
    });
  }
});

Przykład: http://emberjs.jsbin.com/coxexubuwi/1/edit

Mieszaj i dopasuj i baw się dobrze!

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: Ember.RSVP.Promise.cast(['pluto', 'mickey']),
           weather: $.getJSON('weather')
    });
  }, 
  setupController: function(controller, model){
    this._super(controller, model);
    controller.set('favoritePuppy', model.dogs[0]);
  }
});

Przykład: http://emberjs.jsbin.com/joraruxuca/1/edit

 149
Author: Kingpin2k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-07 02:55:17

Używam czegoś takiego jak odpowiedź, którą podał Marcio, ale wygląda to mniej więcej tak:

    var products = Ember.$.ajax({
        url: api + 'companies/' +  id +'/products',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var clients = Ember.$.ajax({
        url: api + 'clients',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var updates = Ember.$.ajax({
        url: api + 'companies/' +  id + '/updates',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var promises = {
        products: products,
        clients: clients,
        updates: updates
    };

    return Ember.RSVP.hash(promises).then(function(data) {
      return data;
    });  
 3
Author: la_antorcha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-08 14:37:30

Jeśli używasz danych Ember, staje się to jeszcze prostsze dla niepowiązanych modeli:

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseArray.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2)
    });
  }
});

Jeśli chcesz odzyskać właściwość obiektu tylko dla model2, Użyj DS.PromiseObject zamiast DS.PromiseArray :

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseObject.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2.get('value'))
    });
  }
});
 2
Author: AWM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 13:53:48

Najnowsza wersja JSON-API zaimplementowana w Ember Data v1.13 bardzo dobrze obsługuje łączenie różnych zasobów w tym samym żądaniu, jeśli nie masz nic przeciwko modyfikacji punktów końcowych API.

W moim przypadku mam session punkt końcowy. Sesja odnosi się do rekordu użytkownika, a Rekord użytkownika odnosi się do różnych modeli, które zawsze chcę ładować przez cały czas. To całkiem miłe, że to wszystko przychodzi z jedną prośbą.

Jedno zastrzeżenie na spec jest takie, że wszystkie zwracane podmioty powinny być w jakiś sposób powiązane z otrzymywanym podmiotem głównym. Wierzę, że ember-data będzie tylko przemierzać wyraźne relacje podczas normalizacji JSON.

W innych przypadkach, teraz wybieram odroczenie ładowania dodatkowych modeli, Dopóki strona nie zostanie już załadowana, tzn. dla oddzielnych paneli danych lub cokolwiek innego, więc przynajmniej strona jest renderowana tak szybko, jak to możliwe. Robiąc to, istnieje pewna strata/zmiana z" automatycznym " stanem ładowania błędów przemyślane.

 2
Author: aceofspades,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-05 17:02:02