Ember Data: can't get a model from data store - ember.js

I have tried to populate a template with Ember Data.
I'm getting a weird problem when I try to find a model inside my DS Store.
I've followed some tutorials but got an irritating error.
The error is 'Error while loading route: undefined'.
What I've tried:
MovieTracker.Store = DS.Store.extend({
url: 'http://addressbook-api.herokuapp.com'
});
MovieTracker.Contact = DS.Model.extend({
first: DS.attr('string'),
last: DS.attr('string'),
avatar: DS.attr('string')
});
MovieTracker.Router.map(function() {
this.resource('contacts');
});
MovieTracker.ContactsRoute = Ember.Route.extend({
model: function(){//works when changing to 'activate:'
//return; //this works! it shows me a simple template and updates URL to index.html#/contacts
return this.store.find('contact');//error: 'Error while loading route: undefined'
}
});
In the Index.html I have a simple #link-to to 'contacts' (application handlebar), it works well.
I have also a simple template called contacts, which works fine when I give up the this.store.find('contact') line.
JSBin: http://emberjs.jsbin.com/OxIDiVU/170/edit?html,js,output
The JSON is in: http://addressbook-api.herokuapp.com/contacts
Can you please give me any advice?
Would you prefer Ember Data at all (1.0 Beta 5).
Another question: a website without precompiling the handlebars is not gonna be a good idea?
Thank you a lot for reading!

When defining the host you define that on the adapter, not the store.
MovieTracker.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://addressbook-api.herokuapp.com'
});
Additionally, you shouldn't define the id on the model, it's there by default
MovieTracker.Contact = DS.Model.extend({
first: DS.attr('string'),
last: DS.attr('string'),
avatar: DS.attr('string')
});
http://emberjs.jsbin.com/OxIDiVU/172/edit
And the newer versions of ember data aren't documented on the website yet, but the transition document should help explain some of the nuances and changes.
https://github.com/emberjs/data/blob/master/TRANSITION.md

Related

Ember Data loading hasMany relation doesn't work in Ember App Kit (EAK)

I'm trying to set up a hasMany relationship between two models and a hasOne (belongsTo in the current version of Ember Data) between the hasMany and hasOne.
I'm working with Ember Data and have a made a RESTful API that works according to Ember's conventions. All the classes can be queried individually.
Bookmark = hasMany -> Termbinding
Termbinding = belongsTo -> Term
Term = belongsTo -> Termbinding
So the goal is to fetch a Bookmark and get the Terms that are attached to it through the Termbinding. I would already be pretty happy to get the Bookmark to Termbinding relation working. I went through all questions posted on here, sadly enough that didn't work.
Router.js
var Router = Ember.Router.extend();
Router.map(function() {
this.resource('bookmarks', { path:'bookmarks'});
this.resource('bookmark', { path:'bookmarks/:bookmark_id' });
this.resource('termbindings', { path:'termbindings' });
this.resource('termbinding', { path:'termbindings/:termbinding_id' });
});
export default Router;
Bookmark.js
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding')
});
export default Bookmark;
Termbinding.js
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark')
});
export default Termbinding;
I hope someone can help me because this is preventing me from using Ember for my bookmark application. Thanks in advance.
It might be wise to explicitly specify your inverses, i.e.
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark', { inverse: 'termbinding' })
});
export default Termbinding;
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding', { inverse: 'bookmarks' })
});
export default Bookmark;
Ember Data will try to map inverses for you, however, it is not without faults. It could possibly be that your pluralization of 'bookmarks' on a DS.belongsTo relationship is throwing off its automatic inverse mapping. Typically for belongsTo you would use the singular, 'bookmark'. Conversely, your hasMany would be termbindings: DS.hasMany('termbinding')
Also, if you could show where you're invoking the models that would be greatly appreciated. Typically I find that creating a JSbin at emberjs.jsbin.com helps me isolate the problem and also provides a collaborative space to debug and experiment.

Emberjs models with relations throws an error: "Cannot set property 'store' of undefined"

I'm trying out ember at my work to see if we should use it for our future applications I am doing a simple test application and I wanted to try out the relations between the models. This is the code I have that defines the models:
var App = Ember.Application.create();
App.Router.map(function () {
this.resource('index', {path: "/"}, function () {
this.resource("config", {path: "/config/:config_id"});
});
});
App.Store = DS.Store.extend();
App.Conf = DS.Model.extend({
module : DS.attr(),
reports: DS.hasMany('report'),
isClean: function() {
return !this.get('reports').isAny('isClean', false);
}.property('reports.#each')
});
App.Report = DS.Model.extend({
country: DS.attr(),
google_account_id: DS.attr(),
web_property_id: DS.attr(),
custom_source_uid: DS.attr(),
isClean: function() {
return (
this.get('country') != '' &&
this.get('google_account_id') != '' &&
this.get('web_property_id') != '' &&
this.get('custom_source_uid') != ''
);
}.property('country', 'google_account_id', 'web_property_id', 'custom_source_uid')
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://playground.loc/battle_of_frameworks/json.php'
});
…and here is the JSON that is being loaded:
The error I get is:
Error while loading route: TypeError: Cannot set property 'store' of undefined
I Googled the problem and it's usually something about naming your models in plural (ie: App.Reports) which I'm not doing. So I am not sure what the problem is here. Can anyone give any insights?
There are several problems in your code.
Your server doesn't provide the payload expected by Ember Data. I would recommend reading this document about customizing your serializer if you can't generate the proper json payload with your backend.
Ember.js is all about convention over configuration. Right now, you are not following those conventions:
attributes are camelcased
App.Report = DS.Model.extend({
googleAccountId: DS.attr() //instead of google_account_id
});
you don't need to create the index route, it comes for free in Ember. So your router should simply look like:
App.Router.map(function () {
this.resource("config", {path: "/config/:config_id"});
});
Are you sure that your backend expects the Config to be served from /config/:config_id and not /configs/:config_id ?
You declare a config resource. The convention is to have a App.Config model and not App.Conf
In order to clean your code, you can also take advantage of computed properties to DRY your code:
App.Report = DS.Model.extend({
country: DS.attr(),
googleAccountId: DS.attr(),
webPropertyId: DS.attr(),
customSourceUid: DS.attr(),
isClean: Ember.computed.and('country', 'googleAccountId', 'webPropertyId', 'customSourceUid')
});
You also need to pay attention when defining a computed property based on an array. The isClean of Config uses isClean of Report but your computed property observes only the elements of your Report association. The correct way of writing it is:
App.Config = DS.Model.extend({
module : DS.attr(),
reports: DS.hasMany('report'),
isClean: function() {
return !this.get('reports').isAny('isClean', false);
}.property('reports.#each.isClean') //make sure to invalidate your computed property when `isClean` changes
});
I hope this helps.

ember.js cannot set property 'store' of undefined

I have been trying to set up an Ember.js application together with a RESTful API i have created in Laravel.
I have encountered a problem trying to get the data trough the store, and depending on my implementation, I get different errors, but never any working implementations.
The ember.js guide have one example, other places have other examples, and most information I find is outdated.
Here's my current code:
App = Ember.Application.create();
App.Router.map(function() {
this.resource("world", function() {
this.resource("planets");
});
});
App.PlanetsRoute = Ember.Route.extend({
model: function() {
return this.store.find('planet');
}
});
App.Planet = DS.Model.extend({
id: DS.attr('number'),
name: DS.attr('string'),
subjectId: DS.attr('number')
});
And when I try to click the link for planets, thats when the error occurs, and I get the following error right now:
Error while loading route: TypeError {} ember-1.0.0.js:394
Uncaught TypeError: Cannot set property 'store' of undefined emberdata.js:15
No request is sent for /planets at all. I had it working with a $.getJSON, but I wanted to try to implement the default ember-data RESTAdapter.
For reference, these are some of the implementations i've tried:
var store = this.get('store'); // or just this.get('store').find('planet')
return store.find('planet', 1) // (or findAl()) of store.findAll('planet');
App.store = DS.Store.create();
I also tried DS.Store.all('planet') as I found it in the ember.js api, but seemed like I ended up even further away from a solution.
Most other implementations give me an error telling me there is no such method find or findAll.
EDIT (Solution)
After alot of back and forward, I managed to make it work.
I'm not sure exactly which step fixed it, but I included the newest versions available from the web (Instead of locally), and the sourcecode now looks like this:
window.App = Ember.Application.create();
App.Router.map(function() {
this.resource("world", function() {
this.resource("planets");
});
});
App.PlanetsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('planet');
}
});
App.Planet = DS.Model.extend({
name: DS.attr(),
subjectId: DS.attr()
});
The error you had is probably due to the fact that you added a "s" plural of your objects.
i.e. if you use
App.Planets = DS.Model.extend({
})
you would get that error.

Creating Child Records in hasMany Relationship with Ember.Js

I haven't found a satisfactory answer through my search, so I figured I'd ask here.
I'm currently using Ember.Js, Ember-Data, and Ember-Firebase-Adapter, and attempting to create a CRUD application which will create a Parent Record, and then subsequent Child Records to said Parent Records.
(note that DS.Firebase.LiveModel is the Firebase adapter equivalent of DS.Model/Ember.Model)
Here are my models, altered to be generic Post/Comment types
App.Post = DS.Firebase.LiveModel.extend({
name: DS.attr('string'),
body: DS.attr('string'),
date: DS.attr('date'),
comments: DS.hasMany('App.Comment', {embedded: 'always'})
});
App.Comment = DS.Firebase.LiveModel.extend({
message: DS.attr('string'),
timestamp: DS.attr('string'),
post: DS.belongsTo('App.Post', {key: "post_id"})
});
(Should my post_id = post?)
And here is my route for creating Comments:
App.PostsCommentRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', App.Comment.find());
}
});
Here's my controller for the PostsCommentRoute:
App.PostsCommentController = Ember.ObjectController.extend({
newMessage: null,
newTimestamp: null,
saveComment: function() {
App.Pbp.createRecord({
message: this.get('newMessage'),
timestamp: this.get('newTimestamp')
})
App.store.commit();
this.set('newMessage', null);
this.set('newTimestamp', null);
}
});
I think I may be missing the serializer? And I've read several things on addArray but the things I tried to plug in did not prove fruitful. Because my comments create fine, however they are not associated to the post in anyway in my JSON.
Is there a way for the created Comments to find the related Post_Id and then associate to said Post when created? So my Post JSON has an array of Comment_Ids which then allows them to be displayed with the post?
Any help, or links with good examples would be much appreciated. I know this is a relatively simple quandary yet I've been stuck on it for some time now :p
What you can try and do is this
post = App.Post.find(1);
post.get('comments').pushObject(App.Comment.createRecord({})); //This will add a new comment to your post and set the post_id as the post id
App.store.commit()
Hope it helps

Finding a model in ember.js

I'm completely new to ember js. I've downloaded the last rc 2 version of ember, ember-data.js 12 revision, and looked at the manual and copy-past this code in order to be able to see the GET request to my server:
App = Ember.Application.create();
App.Router.map(function() {
... some resources...
});
App.Store = DS.Store.extend({
revision: 12 // Default is the REST Adapter
});
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
birthday: DS.attr('date'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var person = App.Person.find(1);
And I get the next error:
Uncaught Error: assertion failed: Your application does not have a
'Store' property defined. Attempts to call 'find' on model classes
will fail. Please provide one as with 'YourAppName.Store =
DS.Store.extend()'
But as I understand I defined the Store property. Maybe I missed something because I havent read the whole manual, but honestly I can't see what's wrong. As I get it after this code I'll see get /post/1/ request to my server, and it should be an amazing thing, but I'm still struggling with this error
This is happening because ember applications are initialized asynchronously. In general you just define classes when js is being loaded, executable code belongs in hooks/callbacks. Mostly you will be using model find() from the model hook on your routes, but if you really need to do something like this right away you can do this:
App.then(function() {
console.log('App has been initialized...');
var person = App.Person.find(1);
});
If you want to experiment with this approach try this jsfiddle which demonstrates using App.then() with the ember-data fixture adapter based on the getting started screencast