EmberJS / Ember Data에서 단일 경로로 여러 모델을 사용하는 방법은 무엇입니까?
문서를 읽어 보면 다음과 같이 경로에 모델을 할당해야하거나 할당해야하는 것처럼 보입니다.
App.PostRoute = Ember.Route.extend({
model: function() {
return App.Post.find();
}
});
특정 경로에서 여러 개체를 사용해야하는 경우 어떻게합니까? 즉, 게시물, 댓글 및 사용자? 로드 할 경로를 어떻게 지정합니까?
영원히 마지막 업데이트 : 계속 업데이트 할 수 없습니다. 따라서 이것은 더 이상 사용되지 않으며 이런 식으로 될 것입니다. 여기 스레드 더 최신 더 나은, 그리고 어떻게 같은 노선에 여러 모델을로드 : EmberJS은?
업데이트 : 원래 답변 embedded: true
에서 모델 정의에서 사용한다고 말했습니다 . 틀 렸습니다. 개정 12에서 Ember-Data는 단일 레코드 또는 수집을 위해 접미사 ( link ) _id
를 사용하여 외래 키를 정의 할 것으로 예상 _ids
합니다. 다음과 유사한 것 :
{
id: 1,
title: 'string',
body: 'string string string string...',
author_id: 1,
comment_ids: [1, 2, 3, 6],
tag_ids: [3,4]
}
나는 바이올린을 업데이트했으며 변경 사항이 있거나이 답변에 제공된 코드에 더 많은 문제가있는 경우 다시 업데이트 할 것입니다.
관련 모델에 대한 답변 :
당신이 설명하는 시나리오의 경우, 내가 의지 할 협회 모델 사이 (설정 만로드 embedded: true
)Post
나는 정의 할 수 있습니다 고려하고, 그 길에서 모델을 DS.hasMany
협회 Comment
모델과 DS.belongsTo
에 대한 연결을 User
모두에 Comment
와 Post
모델. 이 같은:
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')
});
이 정의는 다음과 같이 생성됩니다.
이 정의를 사용하면 find
게시물 이있을 때마다 해당 게시물과 관련된 댓글 모음, 댓글 작성자 및 게시물 작성자 인 사용자에 액세스 할 수 있습니다 . 경로는 간단합니다.
App.PostsPostRoute = Em.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
}
});
그래서에서 PostRoute
(또는 PostsPostRoute
당신이 사용하는 경우 resource
), 내 템플릿에 액세스 할 수 있습니다 컨트롤러의 content
는 IS, Post
나는 단순히 저자 참조 할 수 있도록 모델,author
<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>
( 바이올린 참조 )
관련없는 모델에 대한 답변 :
그러나 시나리오가 설명했던 것보다 조금 더 복잡 하거나 특정 경로에 대해 다른 모델을 사용 (또는 쿼리) 해야하는 경우 Route#setupController
. 예를 들면 :
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));
}
});
이제 Post 경로에있을 때 템플릿이 후크 user
에 설정된대로 컨트롤러 의 속성에 액세스 할 수 있습니다 setupController
.
<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>
( 바이올린 참조 )
Em.Object
여러 모델을 캡슐화하는 데 사용 하는 것은 모든 데이터를 model
후크 로 가져 오는 좋은 방법 입니다. 그러나 뷰 렌더링 후 모든 데이터가 준비되었는지 확인할 수는 없습니다.
또 다른 선택은 Em.RSVP.hash
. 여러 약속을 함께 결합하고 새로운 약속을 반환합니다. 모든 약속이 해결 된 후 해결 된 경우 새 약속입니다. 그리고 setupController
약속이 해결되거나 거부 될 때까지 호출되지 않습니다.
App.PostRoute = Em.Route.extend({
model: function(params) {
return Em.RSVP.hash({
post: // promise to get post
comments: // promise to get comments,
user: // promise to get user
});
},
setupController: function(controller, model) {
// You can use model.post to get post, etc
// Since the model is a plain object you can just use setProperties
controller.setProperties(model);
}
});
이런 식으로 뷰 렌더링 전에 모든 모델을 가져옵니다. 그리고 사용하는 Em.Object
것은 이러한 이점이 없습니다.
또 다른 장점은 약속과 비 약속을 결합 할 수 있다는 것입니다. 이렇게 :
Em.RSVP.hash({
post: // non-promise object
user: // promise object
});
자세한 내용은 https://github.com/tildeio/rsvp.js 를 확인하십시오 Em.RSVP
.
그러나 경로에 동적 세그먼트가있는 경우 Em.Object
또는 Em.RSVP
솔루션을 사용하지 마십시오.
주요 문제는 link-to
. link-to
모델로 생성 된 링크를 클릭하여 URL을 변경 하면 모델이 해당 경로로 직접 전달됩니다. 이 경우 model
후크가 호출되지 않고 setupController
모델이 link-to
제공됩니다.
예는 다음과 같습니다.
경로 코드 :
App.Router.map(function() {
this.route('/post/:post_id');
});
App.PostRoute = Em.Route.extend({
model: function(params) {
return Em.RSVP.hash({
post: App.Post.find(params.post_id),
user: // use whatever to get user object
});
},
setupController: function(controller, model) {
// Guess what the model is in this case?
console.log(model);
}
});
그리고 link-to
코드, 게시물은 모델입니다.
{{#link-to "post" post}}Some post{{/link-to}}
여기서 상황이 흥미로워집니다. URL /post/1
을 사용 하여 페이지를 방문하면 model
후크가 호출되고 setupController
promise가 해결되면 일반 객체를 가져옵니다.
그러나 link-to
링크 를 클릭하여 페이지를 방문하면 post
모델을 전달 PostRoute
하고 경로는 model
후크 를 무시합니다 . 이 경우 setupController
얻을 것이다 post
물론 사용자를 얻을 수의 모델을.
따라서 동적 세그먼트가있는 경로에서 사용하지 마십시오.
잠시 동안을 사용 Em.RSVP.hash
하고 있었지만 문제는 렌더링 전에 모든 모델이로드 될 때까지 뷰를 기다리지 않기를 원한다는 것입니다. 그러나 Ember.PromiseProxyMixin 사용과 관련된 Novelys 의 사람들 덕분에 훌륭한 (그러나 상대적으로 알려지지 않은) 솔루션을 찾았습니다 .
세 가지 시각적 섹션이있는 뷰가 있다고 가정 해 보겠습니다. 이러한 각 섹션은 자체 모델에 의해 뒷받침되어야합니다. 보기 상단의 "splash"콘텐츠를 지원하는 모델은 작고 빠르게로드되므로 정상적으로로드 할 수 있습니다.
경로 만들기 main-page.js
:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('main-stuff');
}
});
그런 다음 해당 Handlebars 템플릿을 만들 수 있습니다 main-page.hbs
.
<h1>My awesome page!</h1>
<ul>
{{#each thing in model}}
<li>{{thing.name}} is really cool.</li>
{{/each}}
</ul>
<section>
<h1>Reasons I Love Cheese</h1>
</section>
<section>
<h1>Reasons I Hate Cheese</h1>
</section>
따라서 템플릿에 치즈와의 사랑 / 증오 관계에 대한 별도의 섹션을 갖고 싶다고 가정 해 보겠습니다. 각 섹션은 어떤 이유로 든 자체 모델에 의해 뒷받침됩니다. 각 모델에는 각 이유와 관련된 광범위한 세부 정보가 포함 된 많은 레코드가 있지만 맨 위에있는 콘텐츠가 빠르게 렌더링되기를 원합니다. 여기에 {{render}}
도우미가 있습니다. 다음과 같이 템플릿을 업데이트 할 수 있습니다.
<h1>My awesome page!</h1>
<ul>
{{#each thing in model}}
<li>{{thing.name}} is really cool.</li>
{{/each}}
</ul>
<section>
<h1>Reasons I Love Cheese</h1>
{{render 'love-cheese'}}
</section>
<section>
<h1>Reasons I Hate Cheese</h1>
{{render 'hate-cheese'}}
</section>
이제 각각에 대한 컨트롤러와 템플릿을 만들어야합니다. 이 예제에서는 사실상 동일하므로 하나만 사용하겠습니다.
라는 컨트롤러를 만듭니다 love-cheese.js
.
import Ember from 'ember';
export default Ember.ObjectController.extend(Ember.PromiseProxyMixin, {
init: function() {
this._super();
var promise = this.store.find('love-cheese');
if (promise) {
return this.set('promise', promise);
}
}
});
PromiseProxyMixin
여기서는 컨트롤러가 약속을 인식하도록 만드는 여기를 사용하고 있음을 알 수 있습니다. 컨트롤러가 초기화되면 Promise가 love-cheese
Ember 데이터를 통해 모델을 로드해야 함을 나타냅니다 . 컨트롤러의 promise
속성 에서이 속성을 설정해야 합니다.
이제 다음과 같은 템플릿을 만듭니다 love-cheese.hbs
.
{{#if isPending}}
<p>Loading...</p>
{{else}}
{{#each item in promise._result }}
<p>{{item.reason}}</p>
{{/each}}
{{/if}}
템플릿에서 약속 상태에 따라 다른 콘텐츠를 렌더링 할 수 있습니다. 페이지가 처음로드되면 '내가 치즈를 좋아하는 이유'섹션이 표시됩니다 Loading...
. Promise가로드되면 모델의 각 레코드와 관련된 모든 이유를 렌더링합니다.
각 섹션은 독립적으로로드되며 주요 콘텐츠가 즉시 렌더링되는 것을 차단하지 않습니다.
이것은 단순한 예이지만 다른 모든 사람들이 저처럼 유용하다고 생각하기를 바랍니다.
여러 행의 콘텐츠에 대해 유사한 작업을 수행하려는 경우 위의 Novelys 예제가 훨씬 더 관련성이 있음을 찾을 수 있습니다. 그렇지 않은 경우 위의 내용이 잘 작동합니다.
이것은 모범 사례와 순진한 접근 방식이 아닐 수 있지만 하나의 중앙 경로에서 여러 모델을 사용할 수있는 방법을 개념적으로 보여줍니다.
App.PostRoute = Ember.Route.extend({
model: function() {
var multimodel = Ember.Object.create(
{
posts: App.Post.find(),
comments: App.Comments.find(),
whatever: App.WhatEver.find()
});
return multiModel;
},
setupController: function(controller, model) {
// now you have here model.posts, model.comments, etc.
// as promises, so you can do stuff like
controller.set('contentA', model.posts);
controller.set('contentB', model.comments);
// or ...
this.controllerFor('whatEver').set('content', model.whatever);
}
});
도움이 되길 바랍니다
다른 모든 훌륭한 답변 덕분에 여기 최고의 솔루션을 간단하고 재사용 가능한 인터페이스로 결합하는 믹스 인을 만들었습니다. 지정한 모델 Ember.RSVP.hash
에 afterModel
대해 in 을 실행 한 다음 속성을의 컨트롤러에 삽입합니다 setupController
. 표준 model
후크를 방해하지 않으므로 여전히 정상으로 정의합니다.
사용 예 :
App.PostRoute = Ember.Route.extend(App.AdditionalRouteModelsMixin, {
// define your model hook normally
model: function(params) {
return this.store.find('post', params.post_id);
},
// now define your other models as a hash of property names to inject onto the controller
additionalModels: function() {
return {
users: this.store.find('user'),
comments: this.store.find('comment')
}
}
});
다음은 믹스 인입니다.
App.AdditionalRouteModelsMixin = Ember.Mixin.create({
// the main hook: override to return a hash of models to set on the controller
additionalModels: function(model, transition, queryParams) {},
// returns a promise that will resolve once all additional models have resolved
initializeAdditionalModels: function(model, transition, queryParams) {
var models, promise;
models = this.additionalModels(model, transition, queryParams);
if (models) {
promise = Ember.RSVP.hash(models);
this.set('_additionalModelsPromise', promise);
return promise;
}
},
// copies the resolved properties onto the controller
setupControllerAdditionalModels: function(controller) {
var modelsPromise;
modelsPromise = this.get('_additionalModelsPromise');
if (modelsPromise) {
modelsPromise.then(function(hash) {
controller.setProperties(hash);
});
}
},
// hook to resolve the additional models -- blocks until resolved
afterModel: function(model, transition, queryParams) {
return this.initializeAdditionalModels(model, transition, queryParams);
},
// hook to copy the models onto the controller
setupController: function(controller, model) {
this._super(controller, model);
this.setupControllerAdditionalModels(controller);
}
});
https://stackoverflow.com/a/16466427/2637573 is fine for related models. However, with recent version of Ember CLI and Ember Data, there is a simpler approach for unrelated models:
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)
});
}
});
If you only want to retrieve an object's property for model2
, use DS.PromiseObject instead of 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'))
});
}
});
Adding to MilkyWayJoe's answer, thanks btw:
this.store.find('post',1)
returns
{
id: 1,
title: 'string',
body: 'string string string string...',
author_id: 1,
comment_ids: [1, 2, 3, 6],
tag_ids: [3,4]
};
author would be
{
id: 1,
firstName: 'Joe',
lastName: 'Way',
email: 'MilkyWayJoe@example.com',
points: 6181,
post_ids: [1,2,3,...,n],
comment_ids: [1,2,3,...,n],
}
comments
{
id:1,
author_id:1,
body:'some words and stuff...',
post_id:1,
}
... I believe the link backs are important so that the full relationship is established. Hope that helps someone.
You could use the beforeModel
or afterModel
hooks as these are always called, even if model
is not called because you're using dynamic segments.
As per the asynchronous routing docs:
The model hook covers many use cases for pause-on-promise transitions, but sometimes you'll need the help of the related hooks beforeModel and afterModel. The most common reason for this is that if you're transitioning into a route with a dynamic URL segment via {{link-to}} or transitionTo (as opposed to a transition caused by a URL change), the model for the route you're transitioning into will have already been specified (e.g. {{#link-to 'article' article}} or this.transitionTo('article', article)), in which case the model hook won't get called. In these cases, you'll need to make use of either the beforeModel or afterModel hook to house any logic while the router is still gathering all of the route's models to perform a transition.
따라서에 themes
속성 이 있다고 가정하면 SiteController
다음과 같은 것을 가질 수 있습니다.
themes: null,
afterModel: function(site, transition) {
return this.store.find('themes').then(function(result) {
this.set('themes', result.content);
}.bind(this));
},
setupController: function(controller, model) {
controller.set('model', model);
controller.set('themes', this.get('themes'));
}
'IT story' 카테고리의 다른 글
Android WebView로 기존 .html 파일로드 (0) | 2020.09.15 |
---|---|
바이트 배열을 문자열로 변환 (Java) (0) | 2020.09.15 |
SQL Server 브라우저를 시작할 수 없습니다. (0) | 2020.09.15 |
Roslyn없이 웹 사이트 게시 (0) | 2020.09.15 |
부모 클래스에서 자식 구성 요소 메서드 호출-Angular (0) | 2020.09.15 |