Letztes Update für immer : Ich kann das nicht ständig aktualisieren. Das ist also veraltet und wird wahrscheinlich so sein. Hier ist ein besserer und aktuellerer Thread. EmberJS: Wie lade ich mehrere Modelle auf derselben Route?
Update: In meiner ursprünglichen Antwort habe ich gesagt, embedded: true
in der Modelldefinition zu verwenden. Das ist falsch In Revision 12 erwartet Ember-Data, dass Fremdschlüssel mit einem Suffix ( Link ) _id
für einen einzelnen Datensatz oder _ids
für die Erfassung definiert werden. Ähnliches wie das Folgende:
{
id: 1,
title: 'string',
body: 'string string string string...',
author_id: 1,
comment_ids: [1, 2, 3, 6],
tag_ids: [3,4]
}
Ich habe die Geige aktualisiert und werde dies erneut tun, wenn sich etwas ändert oder wenn ich weitere Probleme mit dem in dieser Antwort angegebenen Code finde.
Antwort mit verwandten Modellen:
Für das Szenario, das Sie beschreiben, würde ich mich auf Assoziationen zwischen Modellen (Einstellung embedded: true
) verlassen und das Post
Modell nur auf dieser Route laden , da ich eine DS.hasMany
Assoziation für das Comment
Modell und eine DS.belongsTo
Assoziation für das User
sowohl im Comment
als auch im Post
Modell definieren kann. Etwas wie das:
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
posts: DS.hasMany('App.Post'),
comments: DS.hasMany('App.Comment')
});
App.Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
author: DS.belongsTo('App.User'),
comments: DS.hasMany('App.Comment')
});
App.Comment = DS.Model.extend({
body: DS.attr('string'),
post: DS.belongsTo('App.Post'),
author: DS.belongsTo('App.User')
});
Diese Definition würde ungefähr Folgendes ergeben:
Mit dieser Definition habe ich immer dann, wenn ich find
einen Beitrag verfasse, Zugriff auf eine Sammlung von Kommentaren, die diesem Beitrag zugeordnet sind, sowie auf den Autor des Kommentars und den Benutzer, der der Autor des Beitrags ist, da alle eingebettet sind . Die Route bleibt einfach:
App.PostsPostRoute = Em.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
}
});
In PostRoute
(oder PostsPostRoute
wenn Sie verwenden resource
) haben meine Vorlagen Zugriff auf die Controller content
, bei denen es sich um das Post
Modell handelt, sodass ich mich einfach auf den Autor beziehen kannauthor
<script type="text/x-handlebars" data-template-name="posts/post">
<h3>{{title}}</h3>
<div>by {{author.fullName}}</div><hr />
<div>
{{body}}
</div>
{{partial comments}}
</script>
<script type="text/x-handlebars" data-template-name="_comments">
<h5>Comments</h5>
{{#each content.comments}}
<hr />
<span>
{{this.body}}<br />
<small>by {{this.author.fullName}}</small>
</span>
{{/each}}
</script>
(siehe Geige )
Antwort mit nicht verwandten Modellen:
Allerdings, wenn Ihr Szenario ein wenig komplexer als das, was Sie beschrieben, und / oder hat zu verwenden (oder Abfrage) verschiedene Modelle für eine bestimmte Route, würde ich empfehlen , es in zu tun Route#setupController
. Beispielsweise:
App.PostsPostRoute = Em.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
// in this sample, "model" is an instance of "Post"
// coming from the model hook above
setupController: function(controller, model) {
controller.set('content', model);
// the "user_id" parameter can come from a global variable for example
// or you can implement in another way. This is generally where you
// setup your controller properties and models, or even other models
// that can be used in your route's template
controller.set('user', App.User.find(window.user_id));
}
});
Und jetzt, wenn ich mich in der Post-Route befinde, haben meine Vorlagen Zugriff auf die user
Eigenschaft im Controller, wie sie in setupController
Hook eingerichtet wurde:
<script type="text/x-handlebars" data-template-name="posts/post">
<h3>{{title}}</h3>
<div>by {{controller.user.fullName}}</div><hr />
<div>
{{body}}
</div>
{{partial comments}}
</script>
<script type="text/x-handlebars" data-template-name="_comments">
<h5>Comments</h5>
{{#each content.comments}}
<hr />
<span>
{{this.body}}<br />
<small>by {{this.author.fullName}}</small>
</span>
{{/each}}
</script>
(siehe Geige )
post.comments
.Die Verwendung
Em.Object
der Kapselung mehrerer Modelle ist ein guter Weg, um alle Daten in denmodel
Haken zu bekommen . Es kann jedoch nicht sichergestellt werden, dass alle Daten nach dem Rendern der Ansicht vorbereitet werden.Eine andere Wahl ist zu verwenden
Em.RSVP.hash
. Es kombiniert mehrere Versprechen miteinander und gibt ein neues Versprechen zurück. Das neue Versprechen wird gelöst, nachdem alle Versprechen gelöst wurden. UndsetupController
wird erst aufgerufen, wenn das Versprechen gelöst oder abgelehnt wurde.Auf diese Weise erhalten Sie alle Modelle vor dem Rendern der Ansicht. Und die Verwendung
Em.Object
hat diesen Vorteil nicht.Ein weiterer Vorteil ist, dass Sie Versprechen und Nichtversprechen kombinieren können. So was:
Überprüfen Sie dies, um mehr zu erfahren über
Em.RSVP
: https://github.com/tildeio/rsvp.jsVerwenden
Em.Object
oderEm.RSVP
lösen Sie jedoch nicht, wenn Ihre Route dynamische Segmente aufweistDas Hauptproblem ist
link-to
. Wenn Sie die URL durch Klicken auf einenlink-to
mit Modellen generierten Link ändern , wird das Modell direkt an diese Route übergeben. In diesem Fall wird dermodel
Haken nicht aufgerufen undsetupController
Sie erhalten das Modelllink-to
.Ein Beispiel ist wie folgt:
Der Routencode:
Und
link-to
Code, der Beitrag ist ein Modell:Hier wird es interessant. Wenn Sie
/post/1
die Seite mit URL besuchen, wird dermodel
Hook aufgerufen undsetupController
erhält das einfache Objekt, wenn das Versprechen gelöst wurde.Wenn Sie die Seite jedoch per Klick-
link-to
Link besuchen , wird daspost
Modell an übergebenPostRoute
und die Route ignoriert denmodel
Hook. In diesem FallsetupController
erhalten Sie daspost
Modell, natürlich können Sie Benutzer nicht erhalten.Stellen Sie daher sicher, dass Sie sie nicht in Routen mit dynamischen Segmenten verwenden.
quelle
controller.setProperties(model);
, vergessen Sie nicht, diese Eigenschaften mit dem Standardwert zum Controller hinzuzufügen. Andernfalls wird es eine AusnahmeCannot delegate set...
Für eine Weile habe ich verwendet
Em.RSVP.hash
, aber das Problem, auf das ich gestoßen bin, war, dass ich nicht wollte, dass meine Ansicht wartet, bis alle Modelle geladen sind, bevor ich gerendert habe. Ich habe jedoch dank der Mitarbeiter von Novelys eine großartige (aber relativ unbekannte) Lösung gefunden , bei der Ember.PromiseProxyMixin verwendet wird :Angenommen, Sie haben eine Ansicht mit drei unterschiedlichen visuellen Abschnitten. Jeder dieser Abschnitte sollte von einem eigenen Modell unterstützt werden. Das Modell, das den "Splash" -Inhalt oben in der Ansicht unterstützt, ist klein und wird schnell geladen, sodass Sie diesen normal laden können:
Erstellen Sie eine Route
main-page.js
:Anschließend können Sie eine entsprechende Lenkervorlage erstellen
main-page.hbs
:Nehmen wir also an, Sie möchten in Ihrer Vorlage separate Abschnitte über Ihre Hassliebe zu Käse haben, die jeweils (aus irgendeinem Grund) von einem eigenen Modell unterstützt werden. Sie haben in jedem Modell viele Datensätze mit ausführlichen Details zu jedem Grund. Sie möchten jedoch, dass der Inhalt oben schnell gerendert wird. Hier kommt der
{{render}}
Helfer ins Spiel. Sie können Ihre Vorlage folgendermaßen aktualisieren:Jetzt müssen Sie jeweils Controller und Vorlagen erstellen. Da sie für dieses Beispiel praktisch identisch sind, verwende ich nur eine.
Erstellen Sie einen Controller mit dem Namen
love-cheese.js
:Sie werden feststellen, dass wir das
PromiseProxyMixin
hier verwenden, wodurch der Controller vielversprechend wird. Wenn der Controller initialisiert wird, geben wir an, dass das Versprechen daslove-cheese
Modell über Ember Data laden soll . Sie müssen diese Eigenschaft für die Eigenschaft des Controllers festlegenpromise
.Erstellen Sie nun eine Vorlage mit dem Namen
love-cheese.hbs
:In Ihrer Vorlage können Sie je nach Versprechungsstatus unterschiedliche Inhalte rendern. Wenn Ihre Seite zum ersten Mal geladen wird, wird der Abschnitt "Gründe, warum ich Käse liebe" angezeigt
Loading...
. Wenn das Versprechen geladen wird, werden alle Gründe für jeden Datensatz Ihres Modells angezeigt.Jeder Abschnitt wird unabhängig geladen und verhindert nicht, dass der Hauptinhalt sofort gerendert wird.
Dies ist ein vereinfachtes Beispiel, aber ich hoffe, alle anderen finden es genauso nützlich wie ich.
Wenn Sie für viele Inhaltszeilen etwas Ähnliches tun möchten, ist das obige Novelys-Beispiel möglicherweise noch relevanter. Wenn nicht, sollte das oben genannte für Sie gut funktionieren.
quelle
Dies ist möglicherweise keine bewährte Methode und kein naiver Ansatz, zeigt jedoch konzeptionell, wie Sie mehrere Modelle auf einer zentralen Route verfügbar machen würden:
ich hoffe es hilft
quelle
Dank all der anderen hervorragenden Antworten habe ich ein Mixin erstellt, das die besten Lösungen hier zu einer einfachen und wiederverwendbaren Oberfläche kombiniert. Es führt ein
Ember.RSVP.hash
InafterModel
für die von Ihnen angegebenen Modelle aus und fügt dann die Eigenschaften in den Controller einsetupController
. Es stört den Standardhaken nichtmodel
, daher würden Sie dies immer noch als normal definieren.Anwendungsbeispiel:
Hier ist das Mixin:
quelle
https://stackoverflow.com/a/16466427/2637573 ist für verwandte Modelle in Ordnung. Mit der neuesten Version von Ember CLI und Ember Data gibt es jedoch einen einfacheren Ansatz für nicht verwandte Modelle:
Wenn Sie nur die Eigenschaft eines Objekts für abrufen möchten
model2
, verwenden Sie DS.PromiseObject anstelle von DS.PromiseArray :quelle
post
Bearbeitungsroute / -ansicht, in der ich alle vorhandenen Tags in der Datenbank rendern möchte, damit die Verwendung darauf klicken kann, um sie dem zu bearbeitenden Beitrag hinzuzufügen. Ich möchte eine Variable definieren, die ein Array / eine Sammlung dieser Tags darstellt. Würde der oben verwendete Ansatz dafür funktionieren?PromiseArray
(zB "Tags") erstellen . Dann würden Sie es in Ihrer Vorlage an das Auswahlelement des entsprechenden Formulars übergeben.Zur Antwort von MilkyWayJoe hinzufügen, danke übrigens:
kehrt zurück
Autor wäre
Bemerkungen
... Ich glaube, dass die Linkbacks wichtig sind, damit die vollständige Beziehung hergestellt wird. Hoffe das hilft jemandem.
quelle
Sie können die
beforeModel
oderafterModel
Hooks verwenden, da diese immer aufgerufen werden, auch wenn siemodel
nicht aufgerufen werden, weil Sie dynamische Segmente verwenden.Gemäß den asynchronen Routing- Dokumenten:
Angenommen, Sie haben eine
themes
Immobilie auf Ihrem GrundstückSiteController
. Sie könnten so etwas haben:quelle
this
innerhalb des Versprechens würde eine Fehlermeldung geben. Sie könntenvar _this = this
vor der Rückkehr einstellen und dann_this.set(
innerhalb derthen(
Methode tun , um das gewünschte Ergebnis zu erhalten