Ember.js nested routes - javascript

Cheers! I've got routes:
TravelClient.Router.map(function() {
this.resource('tours', function() {
this.resource('tour', { path: ':tour_id' }, function(){
this.route('seats');
});
});
});
And a template:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{...}}
</script>
Seats is an attribute of Tour object:
TravelClient.Tour.find(1).get('seats');
12
And I extend my TourSeats route like this:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id).get('seats');
}
});
Question: how to render tour's seats in template?
UPDATE:
My fixtures looks like that:
TravelClient.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
});
TravelClient.Tour = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
seats: DS.attr('number')
});
TravelClient.Tour.FIXTURES = [{
id: 1,
title: "Brighton, England",
description: "Lorem ipsum dolor ... .",
seats: 12
},...
And I've changed my route extend to this:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id);
}
});
And in template:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{tour.seats}}
</script>
UPDATE 2:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{controller.model.seats}}
</script>
and it gives undefind back.
After some debugging I founded out, that there is no any id in params and params is empty, thats why I can't get the right model in TourSeatsRoute function.

If you're using ember-1.0-pre.4+, the params are only returned for the specific route you're on, not the whole URL. There's some discussion about this here.
I believe the desired approach at this time is to use this.modelFor passing the name of the parent resource you've set up in the parent route. So in your case, it would be:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function() {
return this.modelFor("tour");
}
});

You just need to return the model from the model method:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id);
}
});
And then in your template you can do the following where controller is the context:
{{model.seats}}

I'm still new to EmberJS but I would've written my router and routes like this.
I'm not sure that you need to wrap the post resource inside the posts resource. Note the double plurals in ToursSeatsRoute
TravelClient.Router.map(function() {
this.resource('tours', function() {
this.route('/:tour_id/seats');
});
});
This would give you the following urls:
/tours - you could map this to an ArrayController
/tours/:tour_id/seats - you could map this to an ObjectController
TravelClient.ToursSeatsRoute = Ember.Route.extend({
model: function(params) {
console.log(params);
return TravelClient.Tour.find(params.tour_id);
}
});
Give it a go? Or maybe put your code a in a JSFiddle?

Related

Ember data EmbeddedRecordMixin

I've been trying to make an embedded list of models get loaded. I understood from the demo that EmbeddedRecordsMixin was the way to go but this still fails with: "Error: Assertion Failed: TypeError: factory is undefined" I have tried to separate them in my fixtures and this works just fine so I must be missing something in the embedding part even though it follows this: http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html
Does this doesn't work with Fixtures then?
var App = window.App = Ember.Application.create({
LOG_TRANSITIONS: true
});
var attr = DS.attr;
App.Modificators = DS.Model.extend({
"tpe": attr('string')
});
App.SpecialStuff = DS.Model.extend({
"title": attr('string'),
"body": attr('string'),
"modificators": DS.hasMany('modificators')
});
App.SpecialStuffSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
"modificators": { embedded: 'always' }
}
});
App.SpecialStuff.reopenClass({
FIXTURES: [{
"id": 79,
"title": "fewfew",
"body": "kkk",
"modificators": [{
"id": 1,
"tpe": "vv",
},
{
"id": 2,
"tpe": "mv",
}]
}]
});
App.SpecialStuffIndexRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('special_stuff');
}
});
App.Router.map(function () {
// Add your routes here
this.resource('specialStuff', function() {});
});
Ember.Inflector.inflector.uncountable('modificators');
Ember.Inflector.inflector.uncountable('special_stuff');
App.ApplicationAdapter = DS.FixtureAdapter.extend({});
Ember Data's Fixture Adapter doesn't use a serializer for fetching data. You're better off mocking json calls with something like https://github.com/jakerella/jquery-mockjax and using the rest adapter.
Here's some examples: Ember-data embedded records current state?

How to generate url for a route in Ember.js

I am wondering how is possible to generate url for a given route.
My scenario
I have list of calls (db entity) and user can select several calls and share them with other people via email.
After submition of selected calls is created db row with hash and by relation contains selected calls. Now I need generate link which can be sended by e-mail. This link is not the same route as list of call's route.
So the question is: Is it possible to generate url by route and params in Ember.js? Thank you.
You can use Router#generate which delegates to the router.js library.
Ember 2.5 Example
App = Ember.Application.create();
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' }, function(){
this.route('edit');
});
});
App.Post = Ember.Object.extend();
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
App.Post.create({
id: 5,
title: 'I am post 5'
}),
App.Post.create({
id: 6,
title: 'I am post 6'
}),
App.Post.create({
id: 7,
title: 'I am post 7'
})];
},
actions: {
showUrl: function(post) {
alert(this.router.generate('post.edit', post));
}
}
});
Ember 1.3 Example
App = Ember.Application.create();
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' }, function(){
this.route('edit');
});
});
App.Post = Ember.Object.extend();
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
App.Post.create({
id: 5,
title: 'I am post 5'
}),
App.Post.create({
id: 6,
title: 'I am post 6'
}),
App.Post.create({
id: 7,
title: 'I am post 7'
})];
},
actions: {
showUrl: function(post) {
alert(this.router.generate('post.edit', post));
}
}
});
This is what the {{#link-to ...}} helper uses under the hood.
This can be done in any Ember.js class with the RouterService. It is available since Ember.js 2.15 and in 3.x. Routing functions are no longer confined to Routes.
Ember 2.15, 3.x Example
import Component from '#ember/component';
import { inject as service } from '#ember/service';
export default Component.extend({
router: service(),
actions: {
showUrl(post) {
alert(this.get('router').urlFor('post.edit', post));
}
}
});

Feed an Ember.js template by fetching JSON objects and pushing them in the store

I'm trying to feed a template:
<script type="text/x-handlebars" data-template-name="wineries">
{{#each}}
<p>{{name}}</p>
{{/each}}
</script>
With that route: (look for the comment)
Map.WineriesRoute = Ember.Route.extend({
model: function() {
var store = this.get('store');
return Ember.$.getJSON('/api/wineries').then(function(response) {
if (response.success) {
response.data.forEach(function(winery) {
store.push('winery', winery);
});
}
// what to do here?
return store.findAll('winery');
});
}
});
And that model:
Map.Winery = DS.Model.extend({
name: DS.attr('string'),
address: DS.attr('string'),
address_2: DS.attr('string'),
city: DS.attr('string'),
stateprovince: DS.attr('string'),
country: DS.attr('string'),
latitude: DS.attr('float'),
longitude: DS.attr('float'),
full_address: function () {
return this.get('address') + ' ' + this.get('city') + ' ' + this.get('stateprovince') + ' ' + this.get('country');
}.observes('address', 'city', 'stateprovince', 'country')
});
I'm getting started with Ember.js and reading LOTS of docs but I'm stuck as I don't know how to handle the store too much even after reading the doc page.
1) What should I do to properly feed the store with the objects?
2) What should I do to properly return the objects after having fed the store?
3) Any other ember-related suggestions?
EDIT:
It seems ember-data isn't what I'm looking for, ember-model seems more fitting for my use-case.
Thanks!
First of all: Why do load and push your server data "manually"?
Using DS.RESTAdapter or DS.ActiveModelAdapter you can let ember-data load your items automagically from a REST API. See here for more details.
Your could then simplify your route class like this:
Map.WineriesRoute = Ember.Route.extend({
model: function() {
return this.store.find('winery');
}
});
TomShreds - if you use the RESTAdapter as Mutual Exception suggests (which I advise too), then you can manually set how models are pluralized:
DS.RESTAdapter.configure("plurals", { winery: "wineries" });
Original answer here: Where do I specify the pluralization of a model in Ember Data?

Ember route transitions from one nested object to another

Here is the issue I'm having.
Say you have an app with two models, Project and Post. All posts belong in a specific project. So, the paths to the posts contain the project ID as well (example.com/:project_id/:post_id).
How can I transition from post X on project A to post Y in project B? Simply calling transitionToRoute('post', postA) from post B's route will retain post B's project ID in the url.
Here's a fiddle describing my predicament. As you can see, when using the project links at the top of the page, the correct posts appear in the correct projects. However, click the link after "other post" and you'll see how Ember is happy to display the post in the context of the incorrect project.
How can I transition between these "cousin" routes in Ember?
The JS:
window.App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter
});
App.store = App.Store.create();
App.Router.map(function(match) {
this.resource('projects');
this.resource('project', {path: ':project_id'}, function(){
this.resource('post', {path: ':post_id'});
});
});
App.Project = DS.Model.extend({
title: DS.attr('string'),
posts: DS.hasMany('App.Post')
});
App.Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
project: DS.belongsTo('App.Project')
});
App.Project.FIXTURES = [
{
id: 1,
title: 'project one title',
posts: [1]
},
{
id: 2,
title: 'project two title',
posts: [2]
}
];
App.Post.FIXTURES = [
{
id: 1,
title: 'title',
body: 'body'
},
{
id: 2,
title: 'title two',
body: 'body two'
}
];
App.ApplicationController = Ember.ObjectController.extend({
projects: function() {
return App.Project.find();
}.property()
});
App.PostController = Ember.ObjectController.extend({
otherPost: function(){
id = this.get('id');
if (id == 1) {
return App.Post.find(2);
} else {
return App.Post.find(1);
}
}.property('id')
});
And the templates:
<script type="text/x-handlebars" data-template-name="application">
{{#each project in projects}}
<p>{{#linkTo project project}}{{project.title}}{{/linkTo}}</p>
{{/each}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="project">
<h2>{{title}}</h2>
{{#each post in posts}}
{{#linkTo post post}}{{post.title}}{{/linkTo}}
{{/each}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="post">
<h3>{{title}}</h3>
<p>{{body}}</p>
other post: {{#linkTo post otherPost}}{{otherPost.title}}{{/linkTo}}
</script>
I found 3 issues.
1. Your belongsTo fixture data is missing the id's they belong to.
App.Post.FIXTURES = [
{
id: 1,
title: 'title',
body: 'body',
project:1
},
{
id: 2,
title: 'title two',
body: 'body two',
project:2
}
];
2. When you transition to a resource, if you only send in a single model, it will only change that resource's model, if you want to update multiple models in the path, send in all the models necessary
{{#linkTo 'post' otherPost.project otherPost}}{{otherPost.title}
3. linkTo routes should be in quotes. (in the future it won't work properly without them), see example above
http://jsfiddle.net/3V6cy/1
BTW, thanks for setting up the jsfiddle, it makes me like a million times more likely to answer a question. Good luck working with ember, we love it!

Infinite Loop in Ember-Data clearRelationships?

Inquiry:
Can anybody tell me why I might be getting an infinite loop when attempting to delete an Ember-Data Model. Stepping through the crash, the issue appears to be in clearRelationships, but no matter how minimal I attempt to make the Model relationships I can't seem to get away from the infinite loop, without avoiding them all together.
Relevant Code:
//// Config
App = Ember.Application.create();
App.Adapter = DS.RESTAdapter.extend();
App.store = DS.Store.create({
revision: 11,
adapter: App.Adapter.create()
});
App.Router = Ember.Router.extend({});
App.Router.map(function() {
this.resource('main', { path: '/' });
});
//// Models
App.Scientist = DS.Model.extend({
name: DS.attr('string'),
tests: DS.hasMany('App.Tests'),
criteria: DS.belongsTo('App.Criteria')
});
App.Test = DS.Model.extend({
name: DS.attr('string'),
scientist: DS.belongsTo('App.Scientist'),
criteria: DS.belongsTo('App.Criteria')
});
App.Criteria = DS.Model.extend({
name: DS.attr('string'),
scientist: DS.belongsTo('App.Scientist'),
test: DS.belongsTo('App.Test'),
resources: DS.hasMany('App.Resource')
});
App.Resource = DS.Model.extend({
name: DS.attr('string'),
criteria: DS.belongsTo('App.Criteria')
});
//// Pre-Load Models
App.store.loadMany(App.Test,
[{id:'1', scientist_id:'1', name:'gravity', criteria_id:'2'},
{id:'2', scientist_id:'1', name:'not gravity', criteria_id:'3'}]);
App.store.load(App.Scientist,
{id:'1', name:'Bill', tests:['1', '2'], criteria_id:'1'});
App.store.load(App.Criteria,
{id:'1', name:'control', scientist_id:'1', test_id:null, resources:['1']});
App.store.loadMany(App.Criteria,
[{id:'2', name:'variation1', scientist_id:null, test_id:'1', resources:['2','3']},
{id:'3', name:'variation2', scientist_id:null, test_id:'2', resources:['4','5']}]);
App.store.loadMany(App.Resource,
[{id:'1', name:'resource1', criteria_id:'1'},
{id:'2', name:'resource2', criteria_id:'2'},
{id:'3', name:'resource3', criteria_id:'2'},
{id:'4', name:'resource4', criteria_id:'3'},
{id:'5', name:'resource5', criteria_id:'3'}]);
var filter = App.Test.filter(
function(model) { if (model.get('isLoaded') === true) { return model; } }
);
App.MainRoute = Ember.Route.extend({
setupController: function(controller, model) {
controller.set('tests', filter);
}
});
///// Controller
App.MainController = Ember.ArrayController.extend({
name: 'Main',
createTest: function() {
App.Test.createRecord();
App.store.commit();
},
removeTest: function(test) {
test.deleteRecord();
App.store.commit();
}
});
Steps to Reproduce:
http://jsfiddle.net/hilem/GMt7H/
1) Open Browser Console.
2) Run the fiddle.
3) Watch console as you hit remove on one of the list items.
Update 1 (8:44PM 1/27/2013)
Additional Context: This is using ember-1.0.0-pre.4.js && the latest commit of ember-data on master as of 1/27/2013. I also added a bit more to the example code above.
Update 2 (5:25PM 2/1/2013)
Bump! Issue still exists, there seems to be quite a few issues involving deleteRecord lately on github issue tracker that sound similar to my issue. Here's a link to my specific issue on the tracker:
https://github.com/emberjs/data/issues/671
It's a bug. This pull request on Github fixed it for me. https://github.com/emberjs/data/pull/715
I was having a similar issue. I had models like these
App.User = DS.Model.extend({
account: DS.belongsTo('App.Account'),
name: DS.attr('string')
});
App.Account = DS.Model.extend({
user: DS.belongsTo('App.User'),
type: DS.attr('string')
});
The recursion isn't actually happening in clearRelationships but in this section of the ember.js set method
var meta = obj[META_KEY], desc = meta && meta.descs[keyName],
isUnknown, currentValue;
if (desc) {
desc.set(obj, keyName, value);
} else {
....
}
when I deleted the User it tried to clearRelationships which calls set(this, "account", null) which eventually gets to the section above which calls set again and again and again.
I'm not sure the right way to fix this but I got it to work in my situation by removing the user belongsTo relationship on the account. so my new models look like this
App.User = DS.Model.extend({
account: DS.belongsTo('App.Account'),
name: DS.attr('string')
});
App.Account = DS.Model.extend({
// user: DS.belongsTo('App.User'),
type: DS.attr('string')
});

Categories

Resources