ember-data find using a model fetched using other find's result - ember.js

I am using this settup:
Ember : 1.10.0
Ember Data : 1.0.0-beta.16
jQuery : 1.11.2
ember-localstorage-adapter: 0.5.2
I managed to use the ember-cli to store some data in my datastore (Localstorage)
Now, I would like to retrieve the data. I have 3 classes in my model:
mtg-item.js
name: DS.attr('string'),
material: DS.attr('string'),
description: DS.attr('string')
mtg-point.js
long: DS.attr('string'),
lat: DS.attr('string')
mtg-item-at-point.js
item: DS.belongsTo('mtgItem', {inverse: null}),
position: DS.belongsTo('mtgPoint', {inverse: null})
Here are the data in localstorage:
mantrailling-item: "{"mtgItem":{"records":{"an0jf":{"id":"an0jf","name":"chaussette","material":"tissu","description":"carré de tissus"}}}}"
mantrailling-item-at-point: "{"mtgItemAtPoint":{"records":{"r7v07":{"id":"r7v07","item":"an0jf","position":"qqnpa"}}}}"
mantrailling-point: "{"mtgPoint":{"records":{"qqnpa":{"id":"qqnpa","long":"0","lat":"0"}}}}"mantrailling-style: "{"mtgStyle":{"records":{"rggrm":{"id":"rggrm","name":"default","path":null}}}}"__proto__: Storage
when I try to retrieve the data, I have no problem retrieving the mtgItem and the mtgPoint.
The issue is when trying to retrieve the mtgItemAtPoint.
I get an assert error:
Error: Assertion Failed: You cannot add a 'undefined' record to the
'mtgItemAtPoint.item'. You can only add a 'mtgItem' record to this
relationship.
When debugging, I observed that it occured when trying to set the mtgItem.
I narrowed the search in the belongs-to.js file line 70.
var type = this.relationshipMeta.type;
Ember.assert("You cannot add a '" + newRecord.constructor.typeKey + "' record to the '" + this.record.constructor.typeKey + "." + this.key +"'. " + "You can only add a '" + type.typeKey + "' record to this relationship.", (function () {
if (type.__isMixin) {
return type.__mixin.detect(newRecord);
}
if (Ember.MODEL_FACTORY_INJECTIONS) {
type = type.superclass;
}
return newRecord instanceof type;
})());
The assertion is trying to check if the newRecord is of extends the supertype DS.Model.
When I retrieve the values in debug, here is what I get for type and newRecord:
newRecord.type.__super__.constructor
(subclass of DS.Model)
type
(subclass of DS.Model)
So I don't get why the folowing:
return newRecord instanceof type
returns false?
For the record, I am calling the find like this:
var mtgItem = store.find('mtgItem', {name: "chaussette", material: "tissu"});
mtgItem.then(function(mtgItem) {
var mtgPoint = store.find('mtgPoint', {long: "0", lat: "0"});
mtgPoint.then(function(mtgPoint) {
var mtgItemAtPoint = store.find('mtgItemAtPoint', {item: mtgItem, position: mtgPoint});
});
});

I figured out after some hours of sleep (as usual...)
The problem was that store.find returns an Ember.Enumerable and not a Record. Therefore, you need to iterate trough the results in order to get the proper DS.Model objects. In my case, I needed only one record so I am using the first object.
here is the fix:
var mtgItems = store.find('mtgItem', {name: "chaussette", material: "tissu"});
mtgItems.then(function(mtgItems) {
var mtgItem = mtgItems.get("firstObject");
var mtgPoints = store.find('mtgPoint', {long: "0", lat: "0"});
mtgPoints.then(function(mtgPoints) {
var mtgPoint = mtgPoints.get("firstObject");
var mtgItemAtPoints = store.find('mtgItemAtPoint', {item: mtgItem, position: mtgPoint});
});
});

Related

Ember.js - Get Result

I am a beginner in Ember.js and I would like to get a response result and show in my view (HTML).
My Result:
{"teste": { "code": "1", "message": "hello" } }
My controller in Ember.js:
actions: {
discountCoupon: function() {
var lista = _this.store.find('teste', { "param": "123" });
console.info("return=" + lista.get('code'));
// result return===undefined
console.info("return===" + lista.get('message'));
// result return===undefined
},
...
}
My model:
import DS from 'ember-data';
export default DS.Model.extend({
code: DS.attr('string'),
message: DS.attr('string'),
});
I can't get the return of my backend.
Thanks in advance.
first you need to go and find what ever you are looking for, then you get your results. Remember When javascript promise you something will always give you a result back back....
actions: {
discountCoupon: function(){
var listas = _this.store.find('testes', {
param: "123"
}).then(function(lista){
console.log("return=" + lista.get('code'));
console.log("return===" + lista.get('message'));
});
},
One more thing, because you're using Ember Data and try to search using store.find('model', { queryParams }) Ember expects the backend to return a result in plural:
{"testes": [{"code":"1","message":"hello"}}]

Ember Data model.save misses fields in request body when mapping changed in keyForAttribute

I run into a problem when use Ember-data to save a model. The JSON structure for my model looks like:
{ post: {
id: 1,
name: 'post-1',
trigger: ['trigger-1', 'trigger-2'],
data: ['data-1', 'data-2']
}
}
Because 'data' and 'trigger' are reserved keywords for DS.Model, I created a mapping and renamed them to sc_data and sc_trigger as suggestion by Jurre using
Application.SERIALIZATION_KEY_MAPPINGS = {
'sc_data': 'data',
'sc_trigger': 'trigger'
};
Application.ApplicationSerializer = DS.ActiveModelSerializer.extend({
keyForAttribute: function (attr) {
if (Application.SERIALIZATION_KEY_MAPPINGS.hasOwnProperty(attr)) {
return Application.SERIALIZATION_KEY_MAPPINGS[attr];
} else {
return this._super(attr);
}
}
});
So my model for post looks like:
Application.Post = DS.Model.extend({
name: DS.attr('string'),
sc_trigger: DS.attr(),
sc_data: DS.attr()
});
the sc_trigger and sc_data are renmaed mapping for data and trigger.
It all worked fine when use this.store.find('post') and this.store.find('post', 1), i.e. GET calls. When I try to create a record using this.store.createRecord('post'), it creates a record with the correct attribute name sc_data and sc_trigger.
var newPost = this.store.create('post', {
name: 'test post',
sc_data: [],
sc_trigger: []
})
And the serialize function interprets the mapping correctly as well. newPost.serialize() returns
{
name: 'test post',
data: [],
trigger: []
}
But when I call newPost.save(), in the HTTP request body of the POST call, data and trigger field is missing. It only has
{
name: 'test post'
}
I have no idea why newPost.save() doesn't generate the correct request body when serialize() is working just fine.
Update
I managed to get around this by removing the keyForAttribute mapping and using
Application.ApplicationSerializer = DS.ActiveModelSerializer.extend({
attrs: {
sc_data: {key: 'data'},
sc_trigger: {key: 'trigger'}
}
});
This seems to be the suggested way to handle data with reserved keywords.
Which ember data version and emberjs version are you using?
Try saving with id like-
var newPost = this.store.create('post', {
id:1
name: 'test post',
sc_data: [],
sc_trigger: []
});
Save and create always expects id. So it's better to save/create record with id.

Get server's answer after saving model

I use Ember data with a node js server; the model looks very simple:
Gmcontrolpanel.Product = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
});
Once the node server receives the product.save(), it persists the record in the mysql db, managing the record ID and answers like this:
{
product
{
id: 1,
name: "aaa",
description "bbb"
}
}
I need to get the id of the server's response (not the promise returned by save().then(), where id is null); how can i get it?
Update:
The node server, using express:
GMserver.post('/products', function (req, res) {
rootName = "product";
queryString = 'INSERT INTO products (id, name, descriptions ) VALUES ( '+ counters.prodcuts +', "' + req.body.product.name + '", "' + req.body.product.description + '")';
executeQuery(req, res, queryString);
responseToPost(counters.products, req.body.product, rootName, res);
counters.products++;
});
function executeQuery (req, res, querystring) {
connection.query(queryString, function(err, rows, fields){
if (err) throw err;
});
}
function responseToPost (id, data, rootName, res) {
var result = new Object();
result[rootName] = new Object();
var i = 0;
var answer;
result[rootName].id = id;
for(var key in data)
{
result[rootName][key] = data[key];
}
answer = JSON.stringify(result, null, '\t');
console.log(answer);
res.send(answer);
}
I can see by the log of answer here, that answer is the one written above;
I tried to change responseToPost to send always a static value like this:
result[rootName][key] = 'aaa';
but in Ember, doing
product.save().then(function(savedProduct) {
console.log(savedProduct.get('name'));
}
i get the sumbmitted value of name, not 'aaa' as I expected...
Second Update:
doing in Ember
product.save().then(function(savedProduct) {
console.log(savedProduct);
}
to see what savedProduct is, in Chrome i see the result of the log:
Class {id: null, store: Class, container: Container, currentState: (...), errors: Class…}
__ember1395755543625: "ember548"
__ember1395755543625_meta: Object
__nextSuper: undefined
_attributes: Object
_changesToSync: Object
_data: Object
__ember1395755543625_meta: Meta
_super: function superFunction(){
name: "asdf"
description: "asdfa"
__proto__: Object
_deferredTriggers: Array[0]
_inFlightAttributes: Object
_relationships: Object
_suspendedRelationships: false
_updatingRecordArraysLater: false
container: Container
currentState: (...)
get currentState: function () {
set currentState: function (value) {
data: (...)
errors: Class
id: null
isError: false
store: Class
toString: function () { return ret; }
__proto__: Object
where "asdf" and "asdfa" are the values i typed in the insert form on the app
The record should be updated if that's the JSON returned.
product.save().then(function(record){ //record is the same as product here
console.log(record.get('id'));
});

Observe properties on nested object

Example fiddle: http://emberjs.jsbin.com/aviyUnA/9/edit?html,js,output
This is my model:
{
name: {
title: 'Mr',
first: 'Potato',
last: 'Head'
},
age: 79
}
How do I create a computed property that observes all the keys inside the name object without listing them manually?
fullName: function() {
var name = this.get('name');
return [name.title, name.first, name.last].join(' ');
}.property('name.??')
Thanks for any help!
You can customize the set call of your model: Check if the value being set involves a property of name and if it does, call notifyPropertyChange on name:
App.MyModel = Ember.Object.extend({
set: function(keyName, value) {
this._super(keyName, value);
if (keyName.indexOf('name.') > -1) {
// a property of `name` has changed => notify observers of `name`
this.notifyPropertyChange('name');
}
}
});
Demo: http://emberjs.jsbin.com/akEjubU/1/edit

List all attributes for a specific DS.Model in Ember.js

How can I list all the attributes defined in a model?
For example, if we have a variant for some imaginary blog application:
App.Post = DS.Model.extend({
title: DS.attr('string'),
text: DS.attr('string'),
comments: DS.hasMany('App.Comment')
});
Then, I am looking for a possibility to iterate over the attributes without having an instance of the App.Post model:
# imaginary function
listAttributes(App.Post)
Such a function could yield an array providing name and type of the model attributes:
[{
attribute: "title",
type: "string"
},
{
attribute: "text",
type: "string"
}]
How to achieve that with Ember?
As of Nov 2016 (Ember v2.9.0), the best way to approach this is to use the eachAttribute iterator.
API Reference = http://emberjs.com/api/data/classes/DS.Model.html#method_eachAttribute
modelObj.eachAttribute((name, meta) => {
console.log('key =' + name);
console.log('value =' + modelObj.get(name));
})
Try this:
var attributes = Ember.get(App.Post, 'attributes');
// For an array of attribute objects:
var attrs = attributes.keys.toArray().map(function(key) {return attributes.get(key);} );
// To print the each attributes name and type:
attrs.forEach(function(attr) {console.log(attr.name, attr.type)});
Update for current Ember users
Currently the Ember.Map keys and values are private*, so #Mike Grassotti's answer is no longer applicable.
The listAttributes function should look something like this if you don't want to use private objects:
listAttributes(model) {
const attributes = Ember.get(App.Post, 'attributes'),
tempArr = [];
Ember.get(model.constructor, 'attributes').forEach( (meta, key) =>
temp.push({attribute: key, type: meta.type})
);
return tempArr;
}
* See commit Make Ember.Map keys and values private.