mercredi 22 avril 2015

Duplicate Items after >> store.find('model'. urlParameter)

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&parameterX=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&parameterX=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