Ember data find vs load - ember.js

When you use findQuery in ember-data, does it also load the model localy ? I can't make the following code to work :
App.MyModel = DS.Model.extend {
name: DS.attr('string')
didLoad: ->
console.log('model loaded')
}
Now when I do something like :
objects = App.store.find(App.MyModel, [{name: "john"},{name: "jack"}])
The didLoad callback is not fired. When this callback is fired ?

To implement the query functionality you have to implement the findQuery method in your adapter. This method takes 4 arguments store, type, query, modelArray. When the server returns the data for the query, you have to invoke the load method on the modelArray to fill it with the query result. This method also loads the data into the store, see an example here: http://jsfiddle.net/pangratz666/5HMGd/.
App.store = DS.Store.create({
revision: 4,
adapter: DS.Adapter.create({
find: Ember.K,
findQuery: function(store, type, query, modelArray) {
// expect server to return this array
modelArray.load([{ id: 1, name: 'John'}, { id: 2, name: 'Jack'}]);
}
})
});
App.MyModel = DS.Model.extend({
name: DS.attr('string'),
didLoad: function() {
console.log('model loaded', this.toJSON());
}
});
// invoke query which loads the 2 models, and didLoad is called
App.store.find(App.MyModel, {});
​

Related

ember data not saving foreign key, sent as null

My ember app is not sending my foreign key to the back-end.
I have a table called issues which is has a related table called categories
My model is:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
category_id: DS.belongsTo('category'),
description: DS.attr('string')
});
My route is:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.findAll('issue');
},
actions: {
create: function(){
var issue = this.store.createRecord('issue');
issue.name = this.get('controller').get('newName');
issue.description = this.get('controller').get('newDescription');
issue.category_id = parseInt(this.get('controller').get('newCategory'));
//debugger;
console.log(issue);
issue.save();
},
...
other actions
...
}
}
});
the console.log from above looks like the category_id is getting set correctly:
category_id: 3
description: "foobar"
name: "test"
However my JSON payload that gets sent to the backend looks like:
{"issue":{"name":"test","description":"foobar","category_id":null}}
I tried stepping through by adding a custom serialiser in app/serializers/application.js
export default DS.RESTSerializer.extend({
...
serialize: function(snapshot,options){
console.debug('options='+options);
debugger;
var json = this._super(snapshot, options);;
return json;
}
...
});
But I got lost in all the super calling super indirection.
The snapshot.record has category_id: 3, but the json coming back from the this._super() call has category_id: null
options has includeID:true
Any clues will be much appreciated ...
Ember : 2.0.2
Ember Data : 2.0.0
Your model definition is wrong, when dealing with relationships you define them just as you would define any other attribute, there is no need to use _id.
export default DS.Model.extend({
name: DS.attr('string'),
category: DS.belongsTo('category'),
description: DS.attr('string')
});
As for the creation you should always use setters/getters when dealing with ember objects:
create: function() {
var issue = this.store.createRecord('issue', {
name: this.get('controller').get('newName'),
description: this.get('controller').get('newDescription'),
category: this.get('controller').get('newCategory') // assuming new category is a DS.Model instance of category
});
issue.save();
}
If you wish to stick to the syntax you have you would use issue.set('name', this.get('controller').get('newName')), from the looks of your code it seems you are going about this in the wrong way.
You should have a this.route('new') nested under your issues route, that way you wouldn't have to use the controller to store information.
You would simply set the model of the new route to:
model: function() {
return this.store.createRecord('issue');
}
Your template would make use of the input helpers like so:
{{input value=model.name}} and your action would just get the currentModel and call .save().

Ember data sideloaded mockjax call

I try to model an ajax call via mockjax for ember data.
my models:
App.Service = DS.Model.extend({
name: DS.attr('string'),
service_prices: DS.hasMany('servicePrice')
});
App.ServicePrice = DS.Model.extend({
unit_price: DS.attr('number'),
qty_unit: DS.belongsTo('qtyUnit'),
service: DS.belongsTo('service')
});
App.QtyUnit = DS.Model.extend(Ember.Validations.Mixin, {
name: DS.attr('string'),
});
App.Order = DS.Model.extend({
service: DS.belongsTo('service'),
qty_unit:DS.belongsTo('qtyUnit'),
});
I try to load an order record via mockjax. (Push the button.) According to the console after the call
MOCK GET: /orders/1
Object {url: "/orders/1", type: "GET", isLocal: false, global: true, processData: true…}
Ember data tries a 2nd call
GET http://run.jsbin.com/services/%3CApp.Service:ember518:1%3E 404 (Not Found)
First of all i dont understend why is the 2nd call? Service is sideloaded in my order JSON
var order = {
"order" : {"id":1,"service":1,"qty_unit":4},
"service":[{"id":1,"name":"ENG-GER","service_prices":[1,2]}],
"servicePrices":[
{"id":1,"qty_unit":4,"unit_price":3},
{"id":2,"qty_unit":5,"unit_price":4}
],
"qtyUnits":[
{"id":4,"name":"character"},
{"id":5,"name":"word"},
{"id":6,"name":"sentence"}
]
};
And why tries ember-data call the record App.Service:ember518:1 instead of its id "1"?
Here is the JsBin
http://jsbin.com/finahuna/1/edit
The problem was your setQtyUnits method. You were passing service model rather than just id as expected by your mock endpoint. ember518 is the ember generated name of service model instance in this case which was getting passed rather than id. Modified method is -
setQtyUnits:function(){
var service_id = this.get('model.order.service.id');
if (service_id !== null)
{
var self = this;
//find returns a promise
this.store.find('service',service_id).then(function(service){
//on success
var servicePrices = service.get('service_prices');
var qtyUnits = servicePrices.mapBy('qty_unit');
console.log(qtyUnits);
self.set('qtyUnits', qtyUnits);
});
} else {
this.set('qtyUnits', null);
}
}.observes('model.order.service')
Here is the modified bin - http://jsbin.com/finahuna/4/edit

Cache a record when using Query Params in the call? Ember-data

I have got this route retrieving 2 models:
App.PanelRoute = Ember.Route.extend({
model: function(){
var topologymin = this.store.find('topologymin');
var metricmap = this.store.find('metricmap', { param1: 'something'})
return Ember.RSVP.hash({
topologymin: topologymin,
metricmap: metricmap
});
});
This makes 2 calls:
http://localhost/topologymins
http://localhost/metricmaps?param1=something
If I go to another route and again to this one, it makes again the call with the params, not the other one:
http://localhost/metricmaps?param1=something
But, as its the same call to retrieve the same records I would like them to be cached like in the other call.
How does it know when to call the server and when its not necessary? Is it possible to do that?
My models:
App.Topologymin = DS.Model.extend({
siteGroup: DS.attr('string'),
sites: DS.hasMany('site')
});
App.Metricmap = DS.Model.extend({
profile: DS.attr('string'),
link: DS.attr('string'),
services: DS.attr()
});
When you fire a request based on params Ember Data doesn't know how those params necessarily translate into the models (aka it doesn't know that you have all of the records that have some sort of relationship param1). You can cache it yourself, but then you'd still need some sort of way of knowing those records from other records in your store.
App.PanelRoute = Ember.Route.extend({
model: function(){
var met = this.get('fetchedBeforePromise'),
topologymin = this.store.find('topologymin'),
metricmap = met || this.store.find('metricmap', { param1: 'something'});
this.set('fetchedBeforePromise', metricmap);
return Ember.RSVP.hash({
topologymin: topologymin,
metricmap: metricmap
});
});

TypeError: Unable to set property 'store' of undefined or null reference in ember.js

Below is the code I am using to get data from web API. But every time I try to retrieve data I get same error: Unable to set property 'store' of undefined or null reference in ember.js.
/// <reference path="Lib/ember.js" />
/// <reference path="Lib/ember-data.js" />
var App = Ember.Application.create();
Ember.onerror = function(e) {
alert(e);
};
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
App.store = DS.Store.create({
adapter: App.ApplicationAdapter
});
App.Product = DS.Model.extend({
ID: DS.attr("int"),
Name: DS.attr('string'),
Category: DS.attr('string'),
});
App.ApplicationRoute = Ember.Route.extend({
model: function() {
{{debugger}}
var store1 = this.get("store")
var k = store1.find('product', 1)
return k;
}
});
Your problem is with the returned json from the server. You need to return the following object:
{
product: {
// key value
}
}
If you want to use the DS.RESTAdapter defaults, you can just return the data in that format:
{
product: {
id: 1,
name: 'some name',
category: 'some category'
}
}
And change your model mapping to:
App.Product = DS.Model.extend({
name: DS.attr('string'),
category: DS.attr('string'),
});
If you want to use the capitalized properties like Name, Category. You will need to override some methods of DS.RESTAdapter. If your endpoing doesn't match this format.
Other error is that doesn't exist a DS.attr('int') just DS.attr('number'). But you can remove the id mapping, since is created by default.
This is a jsfiddle with this working http://jsfiddle.net/marciojunior/W5LEH/
Ensure that you are using last versions of Ember.js and Ember-Data.
This is how you define a store for you application:
App.Store = DS.Store.extend({
adapter: App.ApplicationAdapter
});
Note the capital S in Store and extend instead of create.
See Ember-Data Guide

How to use Ember-Data associations in conjunction with an ArrayProxy

I am trying to migrated my app to using Ember-Data as it's persistence mechanism. One thing that strikes me is that I'm not sure if it's still possible to use an arrayProxy for aggregate properties of a hasMany association. In my previous iteration I didn't have any explicit associations, just controllers tied together by specific properties. Now I'd like to take advantage of the association functionality in ember-data, but I am getting errors when I trie to bind the content of my array proxy to the "children" property of the DS.Model. My code is below and there is a jsfiddle here: http://jsfiddle.net/sohara/7p6gb/22/
The error I get is:
Uncaught TypeError: Object App.recipeController.content.ingredients has no method 'addArrayObserver'
I would like to be able to retain a controller layer, even if the data associations are controlleed at the model level. It'd also (ideally) like the child objects to be embedded in the json representation of the parent object in order to avoid multiple server requests.
window.App = Ember.Application.create();
App.store = DS.Store.create({
revision: 3,
adapter: DS.fixtureAdapter
});
App.Ingredient = DS.Model.extend({
name: DS.attr('string'),
price: DS.attr('string')
});
App.Recipe = DS.Model.extend({
name: DS.attr('string'),
ingredients: DS.hasMany('App.Ingredient', {embedded: true} )
});
App.Recipe.FIXTURES = [
{id: 1, name: 'Pizza', ingredients: [{id: 1, name: 'tomato sauce', price: 2, recipeId: 1}]}
];
App.recipeController = Ember.Object.create({
content: App.store.find(App.Recipe, 1)
});
App.ingredientsController = Ember.ArrayProxy.create({
content: 'App.recipeController.content.ingredients',
totalWeigth: function() {
var price = 0;
items = this.get('content');
items.forEach(function(item) {
weight += price;
});
}.property()
});
In App.ingredientsController you need to have contentBinding: 'App.recipeController.content.ingredients', instead of content: ...