i have a problem with Ember & Ember Data.
At first some Information about my Application / Configuration
Infomation about my ember setup:
DEBUG: -------------------------------
ember.debug.js:5197 DEBUG: Ember : 1.11.3
ember.debug.js:5197 DEBUG: Ember Data : 1.0.0-beta.17+canary.4ad70aab2a
ember.debug.js:5197 DEBUG: jQuery : 2.1.3
ember.debug.js:5197 DEBUG: -------------------------------
Infomation my Ember Data Models: On the server side we use a dynamic bean model structure, which produces JSON like this:
"elementBeanWrapper":[
{
"elementBeanList":[
{
"fieldBeanList":[
{
"fieldName":"Name",
"fieldType":"java.lang.Integer"
},
{
"fieldName":"Name",
"fieldType":"java.lang.Integer"
}
]}, .....
I use a Nested Serializer which i found on some other Stackoverflow entry:
/**
Deserialize nested JSON payload into a flat object
with sideloaded relationships.
*/
App.NestedSerializer = DS.RESTSerializer.extend({
/**
Generate a unique ID for a record hash
@param {DS.Store} store
@param {DS.Model} type
@param {Object} hash The record hash object
@return {String} The new ID
*/
generateID: function(store, type, hash){
var id, primaryKey,
serializer = store.serializerFor(type);
type._generatedIds = type._generatedIds || 0;
// Get the ID property name
primaryKey = Ember.get(serializer, 'primaryKey') || 'id';
id = hash[primaryKey];
// Generate ID
if (!id) {
id = ++type._generatedIds;
hash[primaryKey] = id;
}
return id;
},
/**
Sideload a record hash to the payload
@method sideloadRecord
@param {DS.Store} store
@param {DS.Model} type
@param {Object} payload The entire payload
@param {Object} hash The record hash object
@return {Object} The ID of the record(s) sideloaded
*/
sideloadRecord: function(store, type, payload, hash) {
var id, sideLoadkey, sideloadArr, serializer;
// If hash is an array, sideload each item in the array
if (hash instanceof Array) {
id = [];
hash.forEach(function(item, i){
id[i] = this.sideloadRecord(store, type, payload, item);
}, this);
}
// Sideload record
else if (typeof hash === 'object') {
sideLoadkey = type.typeKey.pluralize(); // Sideloaded keys are plural
sideloadArr = payload[sideLoadkey] || []; // Get/create sideload array
id = this.generateID(store, type, hash);
// Sideload, if it's not already sideloaded
if (sideloadArr.findBy('id', id) === undefined){
sideloadArr.push(hash);
payload[sideLoadkey] = sideloadArr;
}
}
// Assume it's already pointing to a sideloaded ID
else {
id = hash;
}
return id;
},
/**
Process nested relationships on a single hash record
@method extractRelationships
@param {DS.Store} store
@param {DS.Model} type
@param {Object} payload The entire payload
@param {Object} hash The hash for the record being processed
@return {Object} The updated hash object
*/
processRelationships: function(store, type, payload, hash) {
// If hash is an array, process each item in the array
if (hash instanceof Array) {
hash.forEach(function(item, i){
hash[i] = this.processRelationships(store, type, payload, item);
}, this);
}
else {
// Find all relationships in this model
type.eachRelationship(function(key, relationship) {
var related = hash[key], // The hash for this relationship
relType = relationship.type; // The model type
this.generateID(store, type, hash);
hash[key] = this.sideloadRecord(store, relType, payload, related);
this.processRelationships(store, relType, payload, related);
}, this);
}
return hash;
},
/**
(overloaded method)
Starts the deserialized of all payloads.
@method normalizePayload
@param {Object} payload
@return {Object} the normalized payload
*/
extract: function(store, type, payload, id, requestType) {
payload = this.normalizePayload(payload);
var rootKeys = Ember.keys(payload);
// Loop through root properties and process extract their relationships
rootKeys.forEach(function(key){
var type = store.container.lookupFactory('model:' + key.singularize()),
hash = payload[key];
// If the key resolves to a model type, sideload any embedded relationships
if (type) {
this.processRelationships(store, type, payload, hash);
}
}, this);
console.log(payload);
return this._super(store, type, payload, id, requestType);
}
,
normalizePayload: function(payload) {
if(payload.elementBeanWrapper){
payload.dashboard = payload.elementBeanWrapper;
delete payload.elementBeanWrapper;
}
return payload;
}
});
App.ApplicationSerializer = App.NestedSerializer;
I created "unwrapper" Models like this (this one is for the search formular):
App.Searchview = DS.Model.extend({
elementBeanList: DS.hasMany('Elementbeanlist')
});
and receive the Items in the route definition:
App.SearchviewRoute = App.AuthenticatedRoute.extend({
model: function(params, transition) {
localStorage.aktivesModul = params.modul_id;
return this.store.find('searchview', params.modul_id);
}
});
and modify the payload with a serializer, to match the name of my routes, so i can use the regular store find method:
App.SearchviewSerializer = App.NestedSerializer.extend({
normalizePayload: function(payload) {
if(payload.elementBeanWrapper){
payload.searchview = payload.elementBeanWrapper;
delete payload.elementBeanWrapper;
}
return payload;
}
});
Okay, now to my problem:
the searchview is dynamically build from the "searchview" model, after i received the json from the server.
in the handelbar template i create it like this: (pseudocode)
{{#each elementbeanlist in model.elementBeanList}}
<form class="inline-form">
{{#each fieldBean in elementbeanlist.fieldBeanList }}
<div class="form-group">
<label>{{fieldBean.fieldName}}</label>
{{input type=fieldBean.fieldType value=fieldBean.fieldValue class="form-control"}}
</div>
{{/ifElement}}
{{/each}}
Also i have a search button, which fire up the search action in the searchview controller.
From the SearchFormula i build up a Queryparameter String:
queryparams = /rest/search/1?identnummer=CL00000001¶meterX=y
and then fire up the find method:
that.store.find('trefferliste', queryparams).then(function(response) {
console.debug("Successfull loaded", response);
that.transitionTo('trefferliste');
}, function(error) {
console.error("Trefferliste mit Fehlern aufgerufen...", error);
that.transitionTo('trefferliste');
}
});
the normal query would call the encoded url "%2Frest%2Fsearch%2F1%3Fidentnummer%3DCL00000001%26parameterX%3Dy"
so i implemented a custom adapter:
App.TrefferlisteAdapter = App.ApplicationAdapter.extend({
buildURL: function(type, id) {
var url = [];
var host = helicDevServer;
var prefix = this.urlPrefix();
if (type) { url.push(this.pathForType(type)); }
//We might get passed in an array of ids from findMany
//in which case we don't want to modify the url, as the
//ids will be passed in through a query param
if (id && !Ember.isArray(id)) { url.push(id); }
if (prefix) { url.unshift(prefix); }
url = url.join('/');
if (!host && url) { url = '/' + url; }
return url;
}
});
which does not encode the url parameters....
The query is fired to the REST Server and i receive good json. But Ember causes an Ember Error and put duplicate Items in the Store.
Error:
Error: Assertion Failed: Expected an object as `data` in a call to `push` for App.Trefferliste , but was undefined
at new Error (native)
at Error.EmberError (/js/libs/ember-stable/ember.debug.js:12061:21)
at Object.Ember.default.assert (/js/libs/ember-stable/ember.debug.js:5162:13)
at ember$data$lib$system$store$$Service.extend.push (/js/libs/ember-canary/ember-data.js:10849:15)
at /js/libs/ember-canary/ember-data.js:4805:24
at Object.Backburner.run (/js/libs/ember-stable/ember.debug.js:217:27)
at ember$data$lib$system$store$$Service.extend._adapterRun (/js/libs/ember-canary/ember-data.js:11143:33)
at /js/libs/ember-canary/ember-data.js:4802:22
at tryCatch (/js/libs/ember-stable/ember.debug.js:46977:16)
at invokeCallback (/js/libs/ember-stable/ember.debug.js:46989:17)
From one JSON Response i get 2 Items Item1 ID: 1 Item2 ID: 1?identnummer=CL00000001¶meterX=y
I hope someone can help me to prevent Ember (Data) to put the duplicate Items in the store, or show me a better way to handle dynamic url parameter with the find method.
Best regards, jan
Aucun commentaire:
Enregistrer un commentaire