Während ich in der Webentwicklung nicht neu bin, bin ich in clientseitigen MVC-Frameworks ziemlich neu. Ich habe einige Nachforschungen angestellt und beschlossen, es mit EmberJS zu versuchen. Ich habe den TodoMVC-Leitfaden durchgesehen und es ergab für mich einen Sinn ...
Ich habe eine sehr einfache App eingerichtet. Indexroute, zwei Modelle und eine Vorlage. Ich habe ein serverseitiges PHP-Skript ausgeführt, das einige Datenbankzeilen zurückgibt.
Eine Sache, die mich sehr verwirrt, ist das Laden mehrerer Modelle auf derselben Route. Ich habe einige Informationen zur Verwendung eines setupControllers gelesen, bin mir aber noch nicht sicher. In meiner Vorlage befinden sich zwei Tabellen, die ich mit nicht verwandten Datenbankzeilen laden möchte. In einer traditionelleren Web-App hätte ich nur SQL-Anweisungen ausgegeben und diese durchlaufen, um die Zeilen zu füllen. Ich habe Schwierigkeiten, dieses Konzept in EmberJS zu übersetzen.
Wie lade ich mehrere Modelle nicht verwandter Daten auf derselben Route?
Ich verwende die neuesten Ember- und Ember Data-Bibliotheken.
Aktualisieren
Obwohl die erste Antwort eine Methode zur Handhabung enthält, erklärt die zweite Antwort, wann sie angemessen ist, und die verschiedenen Methoden, wann sie nicht angemessen ist.
quelle
Antworten:
HINWEIS: Für Ember 3.16+ Apps ist hier derselbe Code, jedoch mit aktualisierter Syntax / Muster: https://stackoverflow.com/a/62500918/356849
Das Folgende gilt für Ember <3.16, obwohl der Code als 3.16+ als vollständig abwärtskompatibel funktionieren würde, aber es macht nicht immer Spaß, älteren Code zu schreiben.
Mit Ember.RSVP.hash können Sie mehrere Modelle laden:
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); } });
Und in Ihrer Vorlage können Sie auf die geladenen Daten verweisen
people
undcompanies
diese abrufen: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>
Dies ist ein Twiddle mit diesem Beispiel: https://ember-twiddle.com/c88ce3440ab6201b8d58
quelle
{{link-to 'index' someModel}}
wird der Modellhaken vollständig übersprungen, wodurch dieses Beispiel unterbrochen wird. Ein robusterer Ansatz besteht darin, zusätzliche Modelle zu laden, insetupController
denen immer ausgeführt wird.IN ACHT NEHMEN:
Sie möchten vorsichtig sein, ob die Rückgabe mehrerer Modelle in Ihrem Modellhaken angemessen ist. Stellen Sie sich diese einfache Frage:
:id
? dhthis.resource('foo', {path: ':id'});
Wenn Sie mit Ja geantwortet haben
Versuchen Sie nicht, auf dieser Route mehrere Modelle vom Modellhaken zu laden !!! Der Grund liegt in der Art und Weise, wie Ember die Verknüpfung mit Routen handhabt. Wenn Sie beim Verknüpfen mit dieser Route ein Modell angeben (
{{link-to 'foo' model}}
,transitionTo('foo', model)
), wird der Modell-Hook übersprungen und das mitgelieferte Modell verwendet. Dies ist wahrscheinlich problematisch, da Sie mehrere Modelle erwartet haben, aber nur ein Modell ausgeliefert wird. Hier ist eine Alternative:Mach es in
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'}); } });
Beispiel: http://emberjs.jsbin.com/cibujahuju/1/edit
Wenn Sie es benötigen, um den Übergang zu blockieren (wie es der Modellhaken tut), geben Sie ein Versprechen vom
afterModel
Haken zurück. Sie müssen die Ergebnisse dieses Hooks manuell verfolgen und an Ihren Controller anschließen.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')); } });
Beispiel: http://emberjs.jsbin.com/diqotehomu/1/edit
Wenn Sie mit Nein geantwortet haben
Lassen Sie uns mehrere Modelle vom Modell-Hook der Route zurückgeben:
App.IndexRoute = Ember.Route.extend({ model: function() { return { model1: ['red', 'yellow', 'blue'], model2: ['green', 'purple', 'white'] }; } });
Beispiel: http://emberjs.jsbin.com/tuvozuwa/1/edit
Wenn darauf gewartet werden muss (z. B. ein Anruf beim Server, eine Art Versprechen)
App.IndexRoute = Ember.Route.extend({ model: function() { return Ember.RSVP.hash({ model1: promise1, model2: promise2 }); } });
Beispiel: http://emberjs.jsbin.com/xucepamezu/1/edit
Im Fall von Ember Data
App.IndexRoute = Ember.Route.extend({ var store = this.store; model: function() { return Ember.RSVP.hash({ cats: store.find('cat'), dogs: store.find('dog') }); } });
Beispiel: http://emberjs.jsbin.com/pekohijaku/1/edit
Wenn eines ein Versprechen ist und das andere nicht, ist alles gut, RSVP wird diesen Wert gerne nur verwenden
App.IndexRoute = Ember.Route.extend({ var store = this.store; model: function() { return Ember.RSVP.hash({ cats: store.find('cat'), dogs: ['pluto', 'mickey'] }); } });
Beispiel: http://emberjs.jsbin.com/coxexubuwi/1/edit
Mix and Match und viel Spaß!
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]); } });
Beispiel: http://emberjs.jsbin.com/joraruxuca/1/edit
quelle
serialize:
Hook in Ihrer Route erstellen ), anstatt ein Modell im Link zu übergeben. Zumodel.model1.someProperty
model.puppyModel.someOtherProperty
Ich benutze so etwas wie die Antwort, die Marcio gegeben hat, aber es sieht ungefähr so aus:
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; });
quelle
then
Funktionen macht keinen Unterschied. Sie vermasseln den asynchronen Code und kehren zurück.Wenn Sie Ember Data verwenden, wird es für nicht verwandte Modelle noch einfacher:
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) }); } });
Wenn Sie nur die Eigenschaft eines Objekts für abrufen möchten
model2
, verwenden Sie DS.PromiseObject anstelle von 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')) }); } });
quelle
Die neueste Version der JSON-API, wie sie in Ember Data v1.13 implementiert ist, unterstützt die Bündelung verschiedener Ressourcen in derselben Anforderung sehr gut, wenn Sie nichts dagegen haben, Ihre API-Endpunkte zu ändern.
In meinem Fall habe ich einen
session
Endpunkt. Die Sitzung bezieht sich auf einen Benutzerdatensatz, und der Benutzerdatensatz bezieht sich auf verschiedene Modelle, die immer geladen werden sollen. Es ist ziemlich schön, dass alles mit einer Anfrage eingeht.Eine Einschränkung gemäß der Spezifikation ist, dass alle von Ihnen zurückgegebenen Entitäten in irgendeiner Weise mit der empfangenen primären Entität verknüpft sein sollten. Ich glaube, dass Glutdaten nur die expliziten Beziehungen durchlaufen, wenn der JSON normalisiert wird.
In anderen Fällen entscheide ich mich jetzt dafür, das Laden zusätzlicher Modelle zu verschieben, bis die Seite bereits geladen ist, dh für separate Datenfelder oder was auch immer, damit zumindest die Seite so schnell wie möglich gerendert wird. Dabei ist ein Verlust / eine Änderung des zu berücksichtigenden "automatischen" Fehlerladezustands zu verzeichnen.
quelle
Nehmen Sie die akzeptierte Antwort und aktualisieren Sie sie für Ember 3.16+
app/routes/index.js
import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class IndexRoute extends Route { @service store; async model() { let [people, companies] = await Promise.all([ this.store.findAll('person'), this.store.findAll('company'), ]); return { people, companies }; } }
Hinweis: Es wird empfohlen, setupController nicht zum Einrichten von Aliasen zu verwenden, da dadurch verschleiert wird, woher Daten stammen und wie sie von der Route zur Vorlage fließen.
In Ihrer Vorlage können Sie also Folgendes tun:
<h2>People:</h2> <ul> {{#each @model.people as |person|}} <li>{{person.name}}</li> {{/each}} </ul> <h2>Companies:</h2> <ul> {{#each @model.companies as |company|}} <li>{{company.name}}</li> {{/each}} </ul>
quelle