How to pass model in Nested routes - emberjs - javascript

I have some nested routes.
App.Router.map(function() {
this.route("dashboard", { path: "/dashboard" });
this.resource("customers", { path: "/customers" },function(){
this.resource("customer",{ path: "/:customer_id" },function(){
this.resource("customer.contact",{path:'/contact'});
});
});
});
TEMPLATES
customers/index
<script type="text/x-handlebars" data-template-name="customers/index">
<h3>Customers</h3>
<table>
{{#each item in model}}
<tr>
<td>{{item.name}}</td>
{{#link-to "customer" item tagName="td"}}Info{{/link-to}}
</tr>
{{/each}}
</table>
</script>
customer
<script type="text/x-handlebars" data-template-name="customer">
<h3>Customer {{name}}</h3>
{{#link-to}}Gallery{{/link-to}}
{{#link-to "customer.contact" this}}Contact{{/link-to}}
{{outlet}}
</script>
contact
<script type="text/x-handlebars" data-template-name="customer/contact">
<h3>Contact info of customer {{name}}</h3>
{{contact}}
</script>
Go Customers->Info
Everything works fine, the link from "customers/index" template passes the item to the customer template where {{name}} will be used. but if i want to pass the context to "contact" template, it doesnt work.
here is the JsBin
http://emberjs.jsbin.com/EveQOke/107

You need to specify a route for customer contact (as well for customer). The reason it works initially is because the link-to is passing the model to the route, so it can skip the non-existent model hook. But when you refresh the page, or hit the contact route, which has no dynamic segment, you need to tell ember that you want to use a model. There is a beta feature that allows all the routes under a resource to use the resource if they don't have another resource defined, but that's still a feature, and isn't yet gold.
App.CustomerRoute = Ember.Route.extend({
model: function(param){
return this.store.find('customer', param.customer_id);
}
});
App.CustomerContactRoute = Ember.Route.extend({
model: function(){
return this.modelFor('customer');
}
});
http://jsbin.com/EveQOke/110/edit

Related

Error when rendering 2 models for a template in Ember.js

I have a template in wish I have 2 components that represents different Models. I need to create a model that contains both datas, for each component. If I have only one model everything works fine, but when I add other one, then this error happens in the console.
Error while processing route: events record is undefined ember$data$lib$system$store$finders$$_find/</<#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:7475:11
Backburner.prototype.run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:222:18
ember$data$lib$system$store$$Store<._adapterRun#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:13133:16
ember$data$lib$system$store$finders$$_find/<#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:7470:1
tryCatch#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53070:14
invokeCallback#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53085:15
publish#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53053:9
#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:31253:7
Queue.prototype.invoke#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:901:9
Queue.prototype.flush#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:965:11
DeferredActionQueues.prototype.flush#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:765:11
Backburner.prototype.end#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:158:9
Backburner.prototype.run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:226:13
run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:19151:12
ember$data$lib$adapters$rest$adapter$$RestAdapter<.ajax/</hash.success#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:1728:15
n.Callbacks/j#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:2:26920
n.Callbacks/k.fireWith#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:2:27738
x#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:4:11251
.send/b/<#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:4:14765
The route of the template that contains the components is:
App.EventsRoute = Ember.Route.extend({
model: function()
{
return Ember.RSVP.hash({
event: this.store.find('event'),
featured: this.store.find('event', 'featured')
});
}
});
Here is my template:
<script type="text/x-handlebars" id="events">
<div class="col-xs-8 pull-left">
{{#each event as |event|}}
{{#event-box event=event}}{{/event-box}}
{{else}}
no events
{{/each}}
...
{{#each featured as |highlight|}}
{{#highlight-event hlevent=highlight}}
{{/highlight-event}}
{{else}}
No Highlights
{{/each}}
...
</script>
Does anyone knows why this error happens and what can I do to solve it?
this.store.find('event', 'featured') is invalid.
Also, find is deprecated.
With the latest Ember Data, you should use store.query().
You'd probably use it like
this.store.query('event', {featured: true})
or
this.store.query('event', {filter: 'featured'})
You'll need to adjust your adapter accordingly. Something like:
urlForQuery: function(query, modelName) {
if (query && query.featured === true) {
delete query.featured;
return this._buildURL(modelName, 'featured');
}
return this._super(query, modelName);
}
This should generate an URL like http://..../events/featured.

Listing fetched records in an Ember template

I'm trying to learn ember by following along with Vic Ramons Ember Rails tutorial.
I'm stuck trying to list the users I have fetched from Rails.
<!-- /templates/users.handlebars -->
<article id="users">
<h2>Users</h2>
<ul>
{{#each user in controller }}
<li>{{ user.email }}</li>
{{/each}}
</ul>
</article>
The /templates/users.handlebars is rendered but no users are listed.
I have checked the JSON output which is ok. When I check the ember inspector tab in chrome I can see 20 'user' models in the Data section.
What is the correct way to list the user records?
/routes/users.js:
Tagged.UsersRoute = Ember.Route.extend({
model: function(){ return this.store.findAll('user') }
});
/models/users.js:
Tagged.User = DS.Model.extend({
email: DS.attr('string')
});
/controllers/users.js:
Tagged.UsersController = Ember.Controller.extend({
});
/router.js:
Tagged.Router.map(function() {
this.resource('users', { path: '/users' })
});
adapters/application_adapter.js:
Tagged.ApplicationAdapter = DS.ActiveModelAdapter.extend({});
The controller JSON response:
{ "users":[
{"id":"5599bbc44d6178d3ae000000","email":"sasha#example.com"},
{"id":"5599bbc54d6178d3ae000001","email":"roberta#example.com"},
{"id":"5599bbc54d6178d3ae000002","email":"reyna.mayert#example.com"}
# ...
] }
<article id="users">
<h2>Users</h2>
<ul>
{{#each user in model }}
<li>{{ user.email }}</li>
{{/each}}
</ul>
</article>
In templates model property of controller is not usually used. If you change you /controllers/users.js to:
Tagged.UsersController = Ember.ArrayController.extend({
});
It should work. Because UsersController becomes a ArrayController which works with #each while normal controller does not.

Emberjs itemController / controller property binding

I've made a jsbin to illustrate my issue.
the binding seems KO with lastname property defined inside the itemController and the fullname value is not updated in my items loop.
What am I doing wrong ?
Controller for item in list is different than one you edit property lastname for, so it will never get updated. Propery lastname has to be specified as Model's property (if using Ember Data you simply don't use DS.attr for it and it won't be persisted). If you use custom library for data persistence you have to manually remove lastname property. You can use Ember Inspector extension to see that there are 5 controllers when you click on item. 4 for each item in list and one is being generated when you click. You edit property lastname for this fifth controller. To solve this you can use:
JavaScript:
App = Ember.Application.create();
App.Router.map(function() {
this.resource('items', function() {
this.resource('item', {path: '/:item_id'});
});
});
App.Model = Ember.Object.extend({
firstname: 'foo',
lastname: 'bar',
fullname: function() {
return this.get('firstname') + ' ' + this.get('lastname');
}.property('firstname', 'lastname')
});
App.ItemsRoute = Ember.Route.extend({
model: function() {
return [App.Model.create({id: 1}), App.Model.create({id: 2}), App.Model.create({id: 3}), App.Model.create({id: 4})];
}
});
App.ItemRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('items').findBy('id', +params.item_id);
}
});
Templates:
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{link-to "items" "items"}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="items">
<ul>
{{#each item in model}}
<li>
{{#link-to 'item' item.id}}
{{item.fullname}} {{item.id}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="item">
{{input value=model.firstname}}
{{input value=model.lastname}}
{{model.fullname}}
</script>
Please keep in mind that ArrayController and ObjectController aren't recommended to use, because they will be deprecated in future. Demo.

Ember multiple Json request Error while loading route Object has no method 'addArrayObserver'

im having a problem with my ember app. Im new to it, and trying to do something fun. So the idea of this app is to go and fetch a list of artists from a server via an ajax call, and then if you click the artist it will go to the server again and fetch the albums via another ajax call.
So the first part is working, it is actually fetching the artists through the ajax call when i click on "music library", but then when clicking on the artist it throws the following error:
Assertion failed: Error while loading route: TypeError: Object [object Object] has no method 'addArrayObserver'
I've read so many different options, and i think im on the right track because by printing on the console i can see that it is actually going to the server and fetching the right artist's albums, but the error is throw at the last moment, so it is not displaying the albums. I was also able to show the albums when reloading or typing the url (not now, since i changed the code to implement the afterModel)
So, here is my code:
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true
});
App.Library = Ember.Object.extend({
name: null,
artist: []
});
App.Library.reopenClass({
loadArtist: function() {
var artistList = Em.A();
$.getJSON('url').then(function(data){
//json parsing, creating a library object and putting it into the array
});
return artistList;
}
});
App.Artist = Ember.Object.extend({
id: null,
name: null,
coverArt: null,
albumCount: null
});
App.Albums = Ember.Object.extend({
albums: []
});
App.Artist.reopenClass({
loadAlbums: function(params) {
var albumsJson = 'url' + params.artist_id +'';
var albumList = Em.A();
$.getJSON(albumsJson).then(function(data){
//parsing json, creating artist objects and pushing them into the array
});
return albumList;
//});
}
});
/*****************************ROUTER**************************************************************************************/
App.Router.map(function() {
// put your routes here
this.resource('library', function() {
this.resource('artist', { path: '/:artist_id'});
});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
var hi = ['Welcome'];
return hi;
}
});
App.LibraryRoute = Ember.Route.extend({
model: function() {
return App.Library.loadArtist();
}
});
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
this.transitionTo('artist', params);
},
afterModel: function(params, transition){
var artist = Em.A();
if(params.artist_id==null){
artist.push(App.Artist.create({artist_id: params.id}));
} else {
artist.push(App.Artist.create({artist_id: params.artist_id}));
}
return App.Artist.loadAlbums(artist[0]);
}
});
/**************************************CONTROLLERS***********************************************************************************/
App.ArtistController = Ember.ArrayController.extend({
needs: "library"
});
App.LibraryController = Ember.ArrayController.extend({});
I would really appreciate some help!
Also, the HTML is as follows:
<script type="text/x-handlebars">
<div class="navbar navbar-default">
<div class="navbar-inner">
<a class="navbar-brand" href="#">My Library</a>
<ul class="nav navbar-nav">
<li>{{#linkTo 'index'}}Home{{/linkTo}}</li>
<li>{{#linkTo 'library'}}Music Library{{/linkTo}}</li>
</ul>
</div>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<div class="container">
{{#each item in model}}
<h1>{{item}}</h1>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="library">
<div class="container">
<div class="row">
<div class="col-md-4">
<table class="table">
{{#each model}}
<tr><td>
{{name}}
</td></tr>
{{#each artist}}
<tr><td>
{{#linkTo 'artist' this}}
{{name}}
{{/linkTo}}
<!--<a {{action 'selectArtist' this}}> {{name}} </a>-->
</td></tr>
{{/each}}
{{/each}}
</table>
</div>
<div class="col-md-8">
<p>Albumes</p>
{{outlet}}
</div>
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="artist">
<div class="container">
<div class="col-md-4">
<table class="table">
<tr><td><p>{{controllers.library.artist.name}}</p></td></tr>
{{#each itemController='album'}}
<tr><td>
{{{name}}}
</td></tr>
{{/each}}
</table>
</div>
</div>
</script>
Thanks a lot!!
To get rid of the error you need to modify the model function of the App.ArtistRoute, to return an array as App.ArtistController is an Ember.ArrayController.
For example,
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
//this.transitionTo('artist', params);
return [];
},
....
Or even place the code of afterModel function in model function to retrieve the albums of this artist.
Although i'm not certain if you really want the model of your artist context to be the albums, it does not look correct to me. I would suggest to make the App.ArtistController aν Ember.ObjectController, assign the model to an App.Artist object and store the albums related to this artist in a property of the App.Artist class. In that case you will need to add a property in App.Artist and create a class of App.Album.
With this in mind have a look at the following example which is a very rough modification of your code (caution the App.ArtistController has not been switched instead its model is an array of albums),
http://emberjs.jsbin.com/AdOfiyiN/2#/library/2
OK, i solved it using this question:
Why isn't my ember.js route model being called?
Instead of putting the logic in the model or afterModel, i just needed to set the controller.
Hope it helps to someone.
Best!

Binding child views and collections within an outlet in emberjs

I'm trying to render a view Team inside of an {{outlet}}. This Team view is comprised of a simple Person view (the team leader), and a collection of Person views (team members). The outlet is set up by calling connectOutlet() on the ApplicationController.
Although the Person child views are rendered in the markup as expected, all the values of name are missing. It sure seems like my bindings and/or controller are not set up properly. What am I missing?
Code and demo: http://jsfiddle.net/aek38/fkKFJ/
The relevant handlebar templates are:
<script type="text/x-handlebars" data-template-name="app">
<div class="container">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="person">
<em>Person name is:</em> {{name}}
</script>
<script type="text/x-handlebars" data-template-name="team">
<h3>Team Leader</h3>
<em>Leader name should be:</em>{{leader.name}}
{{view App.PersonView contentBinding="leader"}}
<h3>Team Members</h3>
{{#collection contentBinding="members"}}
{{view App.PersonView contentBinding="content"}}
{{/collection}}
</script>
Code snippet:
App = Ember.Application.create({
ready: function() {
this.initialize();
},
ApplicationController: Ember.Controller.extend(),
ApplicationView: Ember.View.extend({
templateName: "app"
}),
Person: Ember.Object.extend({
name: "Jane Doe"
}),
PersonController: Ember.ObjectController.extend(),
PersonView: Ember.View.extend({
templateName: "person"
}),
Team: Ember.Object.extend({
members: [],
leader: null
}),
TeamController: Ember.ObjectController.extend(),
TeamView: Ember.View.extend({
templateName: "team"
}),
// ...
You can use
{{view App.PersonView contextBinding="leader"}}
and use {{#each}} instead of {{#collection}} for the members
http://jsfiddle.net/LQTsV/1/
Not very sure whats going on but I tweaked your fiddle to get it working:
http://jsfiddle.net/lifeinafolder/sPcwv/
Seems as if bindings are not working properly in the sense:
contentBinding="this"
works but
contentBinding="this.leader"
doesn't.
Sorry but I couldn't work it out more.
You're setting the content variable on person view via contentBinding that should probably be personBinding. And then in your template you should get the view.person.name.
{{collection}} should be a {{each}} block.
{{#each members}}
{{view App.PersonView personBinding="this"}}
{{/each}}
And this person template will look in the right location for the name.
<script type="text/x-handlebars" data-template-name="person">
<em>Person name is:</em> {{view.person.name}}
</script>
Didn't change your js.
fiddle: http://jsfiddle.net/albertjan/fkKFJ/9/

Categories