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.
Related
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.
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
In my ember app, I have a router with nested resources, like so:
App.Router.map(function () {
this.resource('explore', function() {
this.resource('building', { path: 'building/:slug' });
this.resource('country', { path: ':slug' }, function() {
this.resource('state', {path: ':slug' });
});
});
});
App.CountryRoute = Ember.Route.extend(App.SlugRouter, {
setupController: function(controller, country) {
controller.set('title', 'country detail');
controller.set('model', country);
}
});
App.SlugRouter = Ember.Mixin.create({
serialize: function(model, params) {
var name, object;
object = {};
name = params[0];
object[name] = model.get('slug');
return object;
}
});
App.Building = DS.Model.extend({
country: DS.belongsTo('App.Country'),
name: DS.attr('string'),
slug: DS.attr('string')
});
App.Country = DS.Model.extend({
name: DS.attr('string'),
slug: DS.attr('string'),
buildings: DS.hasMany('App.Building'),
states: DS.hasMany('App.State')
});
Loading the explore route shows a list of buildings received from the server (a django-rest-framework app), each building has a relationship to a country with a belongsTo attribute.
In the explore.index route, I display the list of the buildings, with links to the country route for each building, using {{linkTo this.country}}. The href, however, is loaded as #/explore/undefined, instead of #/explore/<country-name>.
The part that is confusing me is that this only happens the first time that I load the list. If I go to another route, then come back to #/explore, the links render correctly.
In the debugger, putting a breakpoint in the serialize method, I see that the first time that I load the page, the model object is empty (_data.attributes is an empty object). Going to the network tab in the debugger, I see that the a request has been made to the server to get the country data, but the response has not been received yet:
The response is eventually received, since {{this.country.name}} renders correctly, but after it's too late.
Thanks in advance for any responses/tips.
I am using:
Ember: 1.0.0-rc.5,
Handlebars: 1.0.0-rc.4,
jQuery: 1.8.3,
ember-data: 0.13,
ember-data-django-rest-adapter: 0.13
Firstly you are mixing in App.SlugRouter before it's definition. You should be seeing an error like Assertion failed: Expected hash or Mixin instance, got [object Undefined] in the console.
After that you need to load the model for a country by the slug. I don't see this in your Route either. You need something like this in CountryRoute depending on your persistence library.
model: function(params) {
return App.Country.find({slug: params.slug});
}
I suspect the part that is working right now is because your index route is loading the model and passing it in to setupController with the linkTo. Direct loading of the nested page requires configuring that route's model hook.
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
I am just starting with emberjs. I am creating a simple index.html page with two links on top: About and Posts. This is following the standard example on emberjs homepage. I get an error in the browser
"Uncaught TypeError: Cannot call method 'map' of undefined"
So this means that my router is undefined. Why is that?
Here is the app.js code:
var App = Ember.Application.create();
App.router.map(function(){
});
So I tried to define it ...
var App = Ember.Application.create();
App.Router = Ember.Router.extend({
enableLogging: true,
location: 'hash'
});
App.Router.map(function(){
});
I still get the error. I am confused :(.
Make sure you are using the latest version of Ember (1.0.0-RC.2) from http://emberjs.com/.
The example you posted is the old style router which is not used anymore. The new style is explained in this guide and is defined like this:
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
A resource is not an end point. Try the following:
App.Router.map(function() {
this.resource('about', function() {
});
});
So I came across another question on stackoverflow. http://goo.gl/JVEs9. I got a version of ember (1.0.0-pre.2) from the link and re-wrote the code as follows:
var App = Ember.Application.create();
App.Router.map(function(match){
match('/').to('index');
match('about').to('about');
});
This seems to work. I still cannot get:
var App = Ember.Application.create();
App.Router.map(function(){
this.resource('about');
});
I get the error
Uncaught TypeError: Object # has no method 'resource'