EmberJS Dynamic segment error - ember.js

As most Emberists would know, I am in the middle of tearing my hair apart at the moment, trying to overcome this vertical wall that EmberJS has so that I can get to the paradise at it's peak.
Here is what I have at the moment:
<script type="text/x-handlebars" data-template-name="dogs">
<h2> Pick a stack to view its cards </h2>
<ul class="nav">
{{#each model}}
<li>{{#linkTo 'dog' this}} {{name}} {{/linkTo}}</li>
{{/each}}
</script>
My routes are defined like this :
App.Router.map(function(){
this.resource('dogs);
this.resource('dog', '/:dog_id');
});
And accordingly, the Model hook for DogRoute is defined as this :
App.DogRoute = EmberRoute.Extend({
model: function(params){
return App.Dog.find(params.id);
}
});
And finally the model is pretty basic in itself:
App.Dog = DS.Model.extend({
name = DS.attr('string')
});
DS is a bunch of fixtures in my case, so I am not going to bother writing this down. However, this doesn't work and I don't know why. Here is the error I keep getting when I visit dogs route, and expect a bunch of links to dog being rendered:
ember-...rc.5.js (line 356)
uncaught exception: More context objects were passed than there are dynamic segments for the route: dog
Can anybody point out what is being done wrong here ?
Note: If I remove the dynamic segments and simply render a dog route inside of my dogs handlebar, (this from handlebar gets taken off) then the links (dog names) do get rendered. However, I need these routes to be dynamic segments and not just hyperlinks with unique ids autogenerated by ember/handlebars.

Your router declaration is wrong. It should me more like this:
App.Router.map(function() {
this.resource('dogs');
this.resource('dog', {path: '/:dog_id'});
});

The error you get
ember-...rc.5.js (line 356) uncaught exception: More context objects were passed than there are dynamic segments for the route: dog
might be related to your route mappings. You should rather define the routes like this:
App.Router.map(function() {
this.resource('dogs', function() {
this.resource('dog', {path: '/:dog_id'});
});
});
And furthermore since this is ember's default behaviour, (see here under dynamic models):
App.DogRoute = EmberRoute.Extend({
model: function(params){
return App.Dog.find(params.id);
}
});
you don't need to define it explicitly, so you can remove it.
The rest seams to be correct as far I can see.
I've also put togheter a working jsbin, have a look.
Hope it helps.

Related

cant get the model value in template

just started to play with emberjs.dont know if this is stupid question or good one, but I am stuck in this for some days and cant figure out why.
in my router.js
Router.map(function() {
this.resource('posts', {path: '/'});
..........
});
.....
this.resource('post', {path: 'posts/:post_id'});
});
and in the route folder i have posts.js setup as following.it has simple js varible used to hold id , title, and body of articles.
export default Ember.Route.extend({
model: function(){
var posts = [
{
id:'1',
title:'lipsome vesicle',
body:"A liposome is a spherical vesicle"},
{
id:'2',
title:'another lipsome vesicle',
body:"A liposome is a another vesicle"}
]
//console.log(posts)
return posts;
}
});
In posts.hbs, the title of each post is shown as link to the to post. of course by looping through each model as |post| and print link-to post.title.
my post.js file simply get the model for posts and returns it.
export default Ember.Route.extend({
model: function(params) {
return this.modelFor('posts').findBy('id', params.post_id);
}
});
In my template for post.hbs I wanted to simply show the title and body for the post .It would have been more redable if it was like post.title or something like that. but i saw some tutorials that does following.
<h1>{{title}}</h1>
<h1>{{body}}</h1>
the url goes to the localhost:4200/post/1
but I cannot see the title and body
when I checked the value in console for
this.modelFor('posts').findBy('id', params.post_id).title , it prints the title
but view is blank.
I have read somewhere, that the controller is the one that is responsible to get the value from model. in that case too, I dont know how to access the returned model in that controller.
I have watched many tutorials, including the raffler example by railscast, since I have background in rails. but those tuts including lot other seems preety outdated. So for all new learners this is frustating and confusing too. Is there good fresh resources except the emberjs guide?
since the title was being printed in console, after many trials when i tried this trick, i finally managed to get my title in individual post.using Ember inspector plug in when i clicked $E console gave me all the post.so i put that object in array and returned that array.
model: function(params) {
// console.log("hell")
console.log(this.modelFor('posts').findBy('id', params.post_id).title);
var post = [this.modelFor('posts').findBy('id', params.post_id)];
return post;
}
then in my view I looped through the array as:
<ul>
{{#each model as |post|}}
<li>{{post.title}}</li>
{{/each}}
</ul>
but I would like to know better way for this.

ember.js: using routes, templates and outlets to render model data

I'm going round in circles here, trying to pull all the components together to produce the desired view. I feel as if I just need to just tweak the dial to bring it all into focus but at the moment it aludes me.
I have two models - Person and Address - which I have created two templates for; I then want to render these two templates in another 'main' template. At the moment I am not linking them in anyway (eventually 1 person will have many nested addresses) because I want to understand the general principes first.
The two templates work individually using App.Router.map
this.resource('listOfPeopleTemplate', { path: '/' });
or
this.resource('listOfAddressesTemplate', { path: '/' });
but not together or when I add the mainViewTemplate and try to add both into that:
App.Router.map(function () {
//this.resource('listOfAddressesTemplate', { path: '/' });
//this.resource('listOfPeopleTemplate', { path: '/' });
this.resource('mainViewTemplate', { path: '/' });
});
The problem seems centered around:
App.MainViewTemplateRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('listOfPeopleTemplate', {into: 'mainViewTemplate', outlet: 'peops'});
this.render('listOfAddressesTemplate', {into: 'mainViewTemplate', outlet: 'address'});
}
});
Errors returned are "outlet (people) was specified but not found"; and "The value that #each loops over must be an Array..". I can see that I may need to do something about the controller for both the Addresses and People but I don't know what. Fact is, i've got myself into such a muddle I now can't even get the originally successfull version working (with either the address or people displaying in their own template).
I have made the following fiddle http://jsfiddle.net/4gQYs/4/. Please, bring me into focus!
I hope I understood your problem!
I have two routes people and places.
App.Router.map(function(){
this.resource('people');
this.resource('places');
});
I am loading the model for both the controller in model hook of people route.
App.PeopleRoute=Ember.Route.extend({
model:function(){
var places=Em.A();
$.getJSON("js/places.js").then(function(json){places.setObjects(json)});
var placesController=this.generateController('places',places);
placesController.set('content',places);
var people=Em.A();
$.getJSON("js/people.js").then(function(json){people.setObjects(json)});
return people;
},
renderTemplate:function(){
this.render('people',{into:"application",outlet:"people"});
this.render('places',{into:"application",outlet:"places"});
}
});
The following is not needed.May be useful in displaying some related data.
App.PeopleController=Ember.ArrayController.extend({
needs:'places'
});
Now I am rendering the two templates in main application template.
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet people}}
{{outlet places}}
</script>
<script type="text/x-handlebars" data-template-name="people">
{{#each controller}}
<p>{{name}}</p>
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="places">
{{#each controller}}
<p>{{name}}</p>
{{/each}}
</script>

Nested routes causing data reload/replacement?

Posted this on the emberjs forums, but SO seems more appropriate.
Hi! I have two routes called classyears and classyear. They're nested like so:
this.resource('classyears', function(){
this.resource('classyear', { path: '/classyear/:classyear_id'});
});
Posterkiosk.ClassyearsRoute = Ember.Route.extend({
model: function() {
return Posterkiosk.Classyear.find();
}
});
Posterkiosk.ClassyearRoute = Ember.Route.extend({
model: function(model) {
return Posterkiosk.Classyear.find(model.classyear_id);
}
});
My templates are:
Classyears:
<div class="yearList">
{{#each item in model}}
{{#linkTo 'classyear' item}}{{item.id}}{{/linkTo}}
{{/each}}
</div>
{{outlet}}
Classyear:
<div class="transformContainer">
{{trigger sizeComposites}}
{{name}}
{{#each students}}
{{partial student}}
{{/each}}
</div>
(The "trigger" helper is from another SO post. The issue was happening prior to adding it, though)
I'm using the Ember-model RESTAdapter. When I load /classyear/:classyear_id, it looks like classyear is rendering its data twice. Once with the correctly-loaded data, and once with no data loaded. The order appears to be random. If the no-data option happens last, it wipes out the correctly-loaded data, leaving a blank page. Vice-versa, and the page content displays just fine.
Any thoughts?
/edit 2: More info:
It looks as though the 0-record reply is from classyears loading. So, it's likely that the zero-record reply is actually just zero records in my hasMany field "students".
If I load /classyears (no class year specified), it only loads once, to get the class year options. If I then click on a class year, it doesn't reload classyears unless I refresh the page, at which time, it loads both, and if the classyears load (a findall) finishes second, it displays no data on the page (other than the classyears template, correctly populated, at the top).
So... maybe my classyears model isn't handling the hasMany field correctly?
I feel like I'm getting closer, but still not sure what's up.
First of all you need to specify a model for a Student, like so:
Posterkiosk.Student = Ember.Model.extend({
id: Ember.attr(),
name: Ember.attr(),
imageUrl: Ember.attr(),
gradyear: Ember.attr()
});
Posterkiosk.Student.adapter = fixtureAdapter;
Now, in your example you are setting the key for the has many to students, but students is an array of objects, not id's, so create a property called student_ids, and pass an array of ids, now that is your key.
Posterkiosk.Classyear = Ember.Model.extend({
students: Ember.hasMany('Posterkiosk.Student', {key: 'student_ids'})
});
If you set embedded: true, then your Classyears server response should come back like this:
{
classyears: [
{..},
{..}
],
students: [
{..},
{..}
]
}
Otherwise, EM would make a separate call to the endpoint on the Student model, and get that data based on the student_ids property.
See the working jsbin.
Tip: RC.7+ removed the underscore from partials, plus the partial name should be in quotes..

Ember, Ember-data, and jquery-ui.dialog, "Oh my!"

The task:
Open a form in a lightbox to create a new "event"; the opened form should be bookmarkable.
The road blocks:
There are examples of opening a lightbox using {{action}} tags, but could not find one that opened in its own route.
There are many examples using older versions of ember.js.
There is not a lot of documentation related to ember-data and REST (I know, I know...it isn't "production ready").
The problem:
The fields in the form were not being tied to a backing model so "null" was being posted to my servlet (a Spring controller).
My very first iteration was not too far off from the final outcome (jsfiddle). The thing that finally made it works swapping this:
EP.EventsNewRoute = Ember.Route.extend({
...
setupController : function(controller, model) {
controller.set("model", model);
},
...
});
...for this:
EP.EventsNewRoute = Ember.Route.extend({
...
setupController : function(controller, model) {
this.controllerFor("events-new").set("model", model);
},
...
});
The question:
Why does the setupController function need to call controllerFor in order to properly set up the model?
And finally, since I struggled to find a fully-functional example, I wanted to make this accessible (and hopefully discover improvements).
Here's the fiddle: http://jsfiddle.net/6thJ4/1/
Here are a few snippets.
HTML:
<script type="text/x-handlebars">
<div>
<ul>
{{#linkTo "events.new" tagName="li"}}
Add Event
{{/linkTo}}
</ul>
</div>
{{outlet events-new}}
</script>
<script type="text/x-handlebars" data-template-name="events-new">
<form>
<div>
<label>Event Name:</label>
{{view Ember.TextField valueBinding="name"}}
</div>
<div>
<label>Host Name:</label>
{{view Ember.TextField valueBinding="hostName"}}
</div>
</form>
</script>
JavaScript:
...
EP.Router.map(function() {
this.resource("events", function() {
this.route("new");
});
});
EP.EventsNewRoute = Ember.Route.extend({
model : function() {
return EP.Event.createRecord();
},
setupController : function(controller, model) {
//controller.set("model", model); // Doesn't work? Why not?
this.controllerFor("events-new").set("model", model); // What does this do differently?
},
...
});
EP.EventsNewController = Ember.ObjectController.extend({
save : function() {
this.get("content.transaction").commit(); // "content.store" would commit _everything modified_, we only have one element changed, so only "content.transaction" is necessary.
}
});
EP.EventsNewView = Ember.View.extend({
...
});
EP.Event = DS.Model.extend({
name : DS.attr("string"),
hostName : DS.attr("string")
});
Resources:
http://emberjs.com/guides/routing/setting-up-a-controller/
http://emberjs.com/guides/getting-started/toggle-all-todos/ (trying to mimic what I learned, but morph the add-new to a new route)
Writing a LightboxView causes problems / Integrating DOM Manipulating jQuery-Plugins makes actions unusable (lightbox "example")
Dependable views in Ember (another lightbox "example" but doesn't have routes for the lightbox opening)
Why does the setupController function need to call controllerFor in order to properly set up the model?
Ember makes URLs a very integral part of its conventions. This means that the state of your application is represented by the route it is on. You've grokked most of this correctly. But there are couple of subtle nuances, that I will clarify below.
First consider an app with the following URLs,
/posts - shows a list of blog posts.
/posts/1 - shows a single blog post.
And say clicking on a post in the list at /posts takes you to /posts/1.
Given this scenario, there 2 ways a user will get to see the post at /posts/1.
By going to /posts and clicking on the 1st post.
By typing in /posts/1, via bookmarks etc.
In both these cases, the PostRoute for /posts/1 will need the model corresponding to Post id 1.
Consider the direct typing scenario first. To provide a way to lookup the id=1 post model, you would use,
model: function(params) {
return App.Post.find(params.post_id);
}
Your template for post will get the model and it can render using it's properties.
Now consider the second scenario. Clicking on post with id=1 takes you to /posts/1. To do this your template would use linkTo like this.
{{#linkTo 'post' post}} {{post.title}} {{/linkTo}}
Here you are passing in the post model to the linkTo helper. It then serializes the data for the post into a URL, ie:- '/posts/1'. When you click on this link Ember realizes that it needs to render the PostRoute but it already has the post model. So it skips the model hook and directly calls setupController.
The default setupController is setup to simply assign the model on the controller. It's implemented to do something like,
setupController: function(controller, model) {
controller.set('model', model);
}
If you do not need to set custom properties on your controller, you don't need to override it. Note: if you are augmenting it with additional properties you still need to call _super to ensure that the default setupController behaviour executes.
setupController: function(controller, model) {
this._super.apply(this, arguments);
controller.set('customProp', 'foo');
}
One final caveat, If you are using linkTo and the route does not have dynamic segments, then the model hook is still called. This exception makes sense if you consider that you were linking to the /posts route. Then the model hook has to fire else Ember has no data to display the route.
Which brings us to the crux of your question. Nearly there, I promise!
In your example you are using linkTo to get to the EventsNewRoute. Further your EventsNewRoute does not have dynamic segments so Ember does call the model hook. And controller.set("model", model); does work in so much as setting the model on the controller.
The issue is to do with your use of renderTemplate. When you use render or {{render}} helper inside a template, you are effectively getting a different controller to the one you are using. This controller is different from the one you set the model on, hence the bug.
A workaround is to pass the controller in the options, which is why renderTemplate gets this controller as an argument.
renderTemplate: function(controller) {
this.render("events-new", {
outlet : "events-new", controller: controller
});
}
Here's an updated jsfiddle.
Final Note: Unrelated to this question, you are getting the warning,
WARNING: The immediate parent route ('application') did not render into the main outlet and the default 'into' option ('events') may not be expected
For that you need to read this answer. Warning, it's another wall of text! :)

Ember.js router v2 App.Router.map inconsistent in documentation?

I'm creating an app with ember.js. I started on PRE.2 but ended up using ember-data v11 so upgraded to master for ember proper. This meant having to change to the new v2 router interface (which as a side note I think is so much better, so thank you.)
I'm having a couple of problems trying to figure out how it works, I'm deep in the guide but there are a couple of inconsistencies I can't quite get my head around:
1)
It seems there are two different conventions used to configure the route map:
In the 'Templates' section, a match().to() interface is used
App.Router.map(function(match) {
match('/').to('index');
match('/posts').to('posts');
match('/posts/:post_id').to('post');
});
( this method is also used in Tom Dale's gist )
In the 'Routing' section, a resource / route interface is used:
App.Router.map(function() {
this.resource('posts', function() {
this.route('new');
});
});
Here it states that a "resource" should be used for noun routes, and "route" for verb routes.
Then in the "Redirecting to a different URL" section, this noun/verb convention isn't followed:
App.Router.map(function(match) {
this.resource('topCharts', function() {
this.route('choose', { path: '/' });
this.route('albums');
this.route('songs');
this.route('artists');
this.route('playlists');
});
});
My first question is:
Going forward, what is the proper convention for creating routes?
My second question follows on from that and is more relevant to my application:
How do I link from a top level "resource" route to a nested "route" route and pass through the appropriate models?
( there is an example of this in the 'Links' section of the 'Templates' doc, but it pertains to the match().to() interface, and I'm specifically working with the resource/route interface )
Here's my example:
I have created a simple site structure based on streams, a stream consists of details, a set of posts, handles and history. My routing is set up like so:
App.Router.map(function() {
this.resource('streams');
this.resource('stream', { path: '/stream/:stream_id' }, function(){
this.route('details');
this.route('posts');
this.route('handles');
this.route('history');
});
});
My streams route looks like this:
App.StreamsRoute = Ember.Route.extend({
model: function() {
return App.Stream.find();
},
setupController: function(controller, model) {
controller.set('content', model);
}
});
and the template:
<script type="text/x-handlebars" data-template-name="streams">
<ul>
{{#each stream in controller}}
<li>{{#linkTo "stream" stream}} {{stream.title}} {{/linkTo}}</li>
{{/each}}
</ul>
</script>
My stream (singular) route:
<script type="text/x-handlebars" data-template-name="stream">
<nav>
{{#linkTo "stream.details" }}Details{{/linkTo}}
</nav>
{{outlet}}
</script>
Now, I'd like to link to my sub route "details", but I'm not sure what to place in the linkTo so that my model (which is a stream) is passed down into this sub-route:
App.StreamDetailsRoute = Ember.Route.extend({ });
My "details" template just displays some attributes off the stream object.
<script type="text/x-handlebars" data-template-name="stream/details">
<h2>Stream Details</h2>
<p>Id: {{id}}</p>
<p>Title: {{title}}</p>
</script>
I will also want to link through to posts, history and handles sub-routes and be able to display these aggregations based on the stream model. I'm not sure exactly how to do this. I assume I need to use setupController to get the items to display, I'm just not sure how to get the stream object down into these sub routes.
Going forward, what is the proper convention for creating routes?
The Resource/Route approach as described in http://emberjs.com/guides/routing/defining-your-routes/
How do I link from a top level "resource" route to a nested "route" route and pass through the appropriate models?
Specify the name of a route as the first parameter, followed by any contexts that are required. So in your example, when creating a link to "stream.details" from the stream template you need to specify this as the context.
{{#linkTo "stream.details" this}}Details{{/linkTo}}
The approach described in http://emberjs.com/guides/templates/links/ still covers the basics.
When in doubt I recommend checking the test cases for link_helper. For example: https://github.com/emberjs/ember.js/blob/master/packages/ember/tests/helpers/link_to_test.js#L249