2011-12-29 15 views
21

Sto cercando un modo efficace per tradurre il mio oggetto Ember in una stringa JSON, per utilizzarlo in un messaggio websocket sottomodello di Ember a JSON

/* 
* Model 
*/ 

App.node = Ember.Object.extend({ 
    name: 'theName', 
    type: 'theType', 
    value: 'theValue', 
}) 

Il metodo websocket:

App.io.emit('node', {node: hash}); 

l'hash dovrebbe essere la rappresentazione json del nodo. {name: thename, type: theType, ..} Ci deve essere un onliner veloce per fare questo .. Non voglio farlo manualmente poiché ho molti attributi e sono suscettibili di cambiare ..

risposta

14

Come detto si può prendere spunto dalla funzione ember-runtime/lib/core.js#inspect per ottenere le chiavi di un oggetto, vedere http://jsfiddle.net/pangratz666/UUusD/

App.Jsonable = Ember.Mixin.create({ 
    getJson: function() { 
     var v, ret = []; 
     for (var key in this) { 
      if (this.hasOwnProperty(key)) { 
       v = this[key]; 
       if (v === 'toString') { 
        continue; 
       } // ignore useless items 
       if (Ember.typeOf(v) === 'function') { 
        continue; 
       } 
       ret.push(key); 
      } 
     } 
     return this.getProperties.apply(this, ret); 
    } 
}); 

nota, dal momento che impegnarsi 1124005 - che è disponibile in ember-latest.js e nella prossima release - è possibile passare la matrice ret direttamente a getProperties, quindi la dichiarazione di ritorno della funzione getJson simile a questa:

return this.getProperties(ret); 
+0

Per ottenere questo lavoro in IE8, ho dovuto aggiungere un altro tutore se: if (key.indexOf ('__ ember')! == -1) { continua; } – rallrall

+2

Questo non sembra supportare gerarchie nidificate di Jsonables –

-3

Ember. js sembra avere una libreria JSON disponibile. Ho saltato in una console (Firebug) da un esempio Todos e il successivo funzionato per me:

hash = { test:4 } 
JSON.stringify(hash) 

così si dovrebbe essere in grado di cambiare solo la linea in modo

App.io.emit('node', { node:JSON.stringify(hash) }) 
+2

Credo sfida di Stephan consiste nell'ottenere l'rappresentazione hash che può quindi passare a JSON.stringify. Passare il vero oggetto Ember non funziona (sto ricevendo un errore sulla struttura circolare). Scavando attraverso la sorgente Ember, non sono stato in grado di trovare un modo integrato per convertire un oggetto Ember in un hash, quindi potrebbe essere necessario implementarlo manualmente per il proprio oggetto. –

+0

@MirkoFroehlich - Ah, gotcha. Credo di averlo letto in fretta :-) –

11

È possibile ottenere una pianura Oggetto JS (o hash) da un'istanza Ember.Object chiamando getProperties() con un elenco di chiavi.

Se si desidera come una stringa, è possibile utilizzare JSON.stringify().

Ad esempio:

var obj = Ember.Object.create({firstName: 'Erik', lastName: 'Bryn', login: 'ebryn'}), 
    hash = obj.getProperties('firstName', 'lastName'), // => {firstName: 'Erik', lastName: 'Bryn'} 
    stringHash = JSON.stringify(hash); // => '{"firstName": "Erik", "lastName": "Bryn"}' 
+1

E se volessi ottenere tutte le proprietà dal modello Ember? obj.getProperties() non funziona. c'è un modo semplice se non elencare tutte le proprietà. Sarebbe noioso se ci fossero troppe proprietà nel modello. – Rajat

+0

Non c'è un modo, oltre all'uso di 'Object.keys' per estrarre tutte le proprietà da un oggetto Ember. Devi sapere quali proprietà stai usando. – ebryn

+1

Puoi prendere ispirazione da 'Ember.inspect', vedi https://github.com/emberjs/ember.js/blob/master/packages/ember-runtime/lib/core.js#L290-308 – pangratz

3

ho anche lottato con questo. Come dice Mirko, se si passa l'oggetto ember a JSON.stringify si otterrà un errore di riferimento circolare. Tuttavia, se si archivia l'oggetto all'interno di una proprietà e si usa stringify su quell'oggetto, esso funziona, anche sottoproprietà nidificate.

var node = Ember.Object.create({ 
    data: { 
    name: 'theName', 
    type: 'theType', 
    value: 'theValue' 
    } 
}); 

console.log(JSON.stringify(node.get('data'))); 

Tuttavia, questo funziona solo in Chrome, Safari e Firefox. In IE8 ottengo uno stack overflow quindi questa non è una soluzione praticabile.

Ho fatto ricorso alla creazione di schemi JSON sui miei modelli di oggetti e scritto una funzione ricorsiva per iterare sugli oggetti usando le proprietà negli schemi e quindi costruire oggetti Javascript puri che posso quindi stringificare e inviare al mio server. Uso anche gli schemi per la convalida, quindi questa soluzione funziona abbastanza bene per me, ma se si dispone di modelli di dati molto grandi e dinamici, ciò non è possibile. Sono anche interessato a modi più semplici per realizzare questo.

2

Questo lavoro farà al caso tuo?

var json = JSON.stringify(Ember.getMeta(App.node, 'values')); 

Il false è facoltativo, ma sarebbe più performante se non si intende modificare una qualsiasi delle proprietà, che è il caso in base alla tua domanda. Questo funziona per me, ma sono diffidente riguardo al fatto che Ember.meta è un metodo privato e potrebbe funzionare diversamente o non essere disponibile nelle versioni future. (Anche se non mi è immediatamente chiaro se Ember.getMeta() è privato). È possibile visualizzarlo nella sua ultima forma sorgente qui:

https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/lib/utils.js

La proprietà values contiene solo 'normali' le proprietà. È possibile raccogliere proprietà memorizzate nella cache da Ember.meta(App.node, false).cached.Quindi, se si utilizza jQuery con la compilazione, si può facilmente unire questi due oggetti in questo modo:

$.extend({}, Ember.getMeta(App.node, 'values'), Ember.getMeta(App.node, 'cache')); 

Purtroppo, non ho trovato un modo per ottenere sub-strutture come proprietà di matrice in questo modo.

3

I 'Ho scritto un lungo articolo su come è possibile convertire modelli brace in oggetti nativi o JSON che possono aiutare o altri :)

http://pixelchild.com.au/post/44614363941/how-to-convert-ember-objects-to-json

http://byronsalau.com/blog/convert-ember-objects-to-json/

+0

questo collegamento non funziona –

+0

Siti di backup su @KevinPauli - il mio DNS è andato giù per un po 'fastidiosamente. – jennas

+0

ah ok. modificare il post in modo da poter annullare il mio downvote. Devo essere stato di pessimo umore quel giorno, mi dispiace –

4

ho modifed @pangratz soluzione leggermente per fare maneggia gerarchie nidificate di Jsonables:

App.Jsonable = Ember.Mixin.create({ 
    getJson: function() { 
     var v, json = {}; 
     for (var key in this) { 
      if (this.hasOwnProperty(key)) { 
       v = this[key]; 
       if (v === 'toString') { 
        continue; 
       } 
       if (Ember.typeOf(v) === 'function') { 
        continue; 
       } 
       if (App.Jsonable.detect(v)) 
        v = v.getJson(); 
       json[key] = v; 
      } 
     } 
     return json; 
    } 
}); 
1

ho modificato @ soluzione Kevin-Pauli per rendere funziona con le matrici così:

App.Jsonable = Ember.Mixin.create({ 
    getJson: function() { 
     var v, json = {}, inspectArray = function (aSome) { 
      if (Ember.typeof(aSome) === 'array') { 
       return aSome.map(inspectArray); 
      } 
      if (Jsonable.detect(aSome)) { 
       return aSome.getJson(); 
      } 
      return aSome; 
     }; 
     for (var key in this) { 
      if (this.hasOwnProperty(key)) { 
       v = this[key]; 
       if (v === 'toString') { 
        continue; 
       } 
       if (Ember.typeOf(v) === 'function') { 
        continue; 
       } 
       if (Ember.typeOf(v) === 'array') { 
        v = v.map(inspectArray); 
       } 
       if (App.Jsonable.detect(v)) 
        v = v.getJson(); 
       json[key] = v; 
      } 
     } 
     return json; 
    } 
}); 

Ho anche apportato alcune modifiche per ottenere il meglio da entrambi i mondi. Con la seguente versione che ho controllare se l'oggetto Jsonable ha una proprietà specifica che mi informa di quale delle sue proprietà deve essere serializzato:

App.Jsonable = Ember.Mixin.create({ 
    getJson: function() { 
     var v, json = {}, base, inspectArray = function (aSome) { 
      if (Ember.typeof(aSome) === 'array') { 
       return aSome.map(inspectArray); 
      } 
      if (Jsonable.detect(aSome)) { 
       return aSome.getJson(); 
      } 
      return aSome; 
     }; 
     if (!Ember.isNone(this.get('jsonProperties'))) { 
      // the object has a selective list of properties to inspect 
      base = this.getProperties(this.get('jsonProperties')); 
     } else { 
      // no list given: let's use all the properties 
      base = this; 
     } 
     for (var key in base) { 
      if (base.hasOwnProperty(key)) { 
       v = base[key]; 
       if (v === 'toString') { 
        continue; 
       } 
       if (Ember.typeOf(v) === 'function') { 
        continue; 
       } 
       if (Ember.typeOf(v) === 'array') { 
        v = v.map(inspectArray); 
       } 
       if (App.Jsonable.detect(v)) 
        v = v.getJson(); 
       json[key] = v; 
      } 
     } 
     return json; 
    } 
}); 

Sto usando questo piccolo trucco e io sono felice con lui. Spero che aiuti anche gli altri!

Grazie a @pangratz e @ Kevin-Pauli per la loro soluzione!

1

Qui prendo un po 'più avanti la soluzione @leo, @pangratz e @ kevin-pauli. Ora itera non solo con gli array ma anche tramite ha molte relazioni, non controlla se un valore ha il tipo Array ma chiama la funzione isArray definita nell'API di Ember.

CoffeeScript

App.Jsonable = Em.Mixin.create 
    getJson: -> 
    jsonValue = (attr) -> 
     return attr.map(jsonValue) if Em.isArray(attr) 
     return attr.getJson() if App.Jsonable.detect(attr) 
     attr 
    base = 
     if Em.isNone(@get('jsonProperties')) 
     # no list given: let's use all the properties 
     this 
     else 
     # the object has a selective list of properties to inspect 
     @getProperties(@get('jsonProperties')) 
    hash = {} 
    for own key, value of base 
     continue if value is 'toString' or Em.typeOf(value) is 'function' 
     json[key] = jsonValue(value) 
    json 

Javascript

var hasProp = {}.hasOwnProperty; 

App.Jsonable = Em.Mixin.create({ 
    getJson: function() { 
    var base, hash, hashValue, key, value; 
    jsonValue = function(attr) { 
     if (Em.isArray(attr)) { 
     return attr.map(jsonValue); 
     } 
     if (App.Jsonable.detect(attr)) { 
     return attr.getJson(); 
     } 
     return attr; 
    }; 
    base = Em.isNone(this.get('jsonProperties')) ? this : this.getProperties(this.get('jsonProperties')); 
    json = {}; 
    for (key in base) { 
     if (!hasProp.call(base, key)) continue; 
     value = base[key]; 
     if (value === 'toString' || Em.typeOf(value) === 'function') { 
     continue; 
     } 
     json[key] = jsonValue(value); 
    } 
    return json; 
    } 
}); 
+1

aggiungi "var" di fronte a json. ha proposto un cambiamento –

0

ho:

  • codice fisso e semplificato
  • aggiunti prevenzione riferimento circolare
  • uso aggiunto di get value
  • rimosso tutte le proprietà predefinite di un componente vuoto

    //Modified by Shimon Doodkin 
    //Based on answers of: @leo, @pangratz, @kevin-pauli, @Klaus 
    //http://stackoverflow.com/questions/8669340 
    
    App.Jsonable = Em.Mixin.create({ 
        getJson : function (keysToSkip, visited) { 
         //getJson() called with no arguments, 
         // they are to pass on values during recursion. 
    
         if (!keysToSkip) 
          keysToSkip = Object.keys(Ember.Component.create()); 
    
         if (!visited) 
          visited = []; 
    
         visited.push(this); 
    
         var getIsFunction; 
    
         var jsonValue = function (attr, key, obj) { 
          if (Em.isArray(attr)) 
           return attr.map(jsonValue); 
          if (App.Jsonable.detect(attr)) 
           return attr.getJson(keysToSkip, visited); 
          return getIsFunction?obj.get(key):attr; 
         }; 
    
         var base; 
         if (!Em.isNone(this.get('jsonProperties'))) 
          base = this.getProperties(this.get('jsonProperties')); 
         else 
          base = this; 
    
         getIsFunction=Em.typeOf(base.get) === 'function'; 
    
         var json = {}; 
    
         var hasProp = Object.prototype.hasOwnProperty; 
    
         for (var key in base) { 
    
          if (!hasProp.call(base, key) || keysToSkip.indexOf(key) != -1) 
           continue; 
    
          var value = base[key]; 
    
          // there are usual circular references 
          // on keys: ownerView, controller, context === base 
    
          if (value === base || 
           value === 'toString' || 
           Em.typeOf(value) === 'function') 
           continue; 
    
          // optional, works also without this, 
          // the rule above if value === base covers the usual case 
          if (visited.indexOf(value) != -1) 
           continue; 
    
          json[key] = jsonValue(value, key, base); 
    
         } 
    
         visited.pop(); 
         return json; 
        } 
    }); 
    
    /* 
    example: 
    
    DeliveryInfoInput = Ember.Object.extend(App.Jsonable,{ 
    jsonProperties: ["title","value","name"], //Optionally specify properties for json 
    title:"", 
    value:"", 
    input:false, 
    textarea:false, 
    size:22, 
    rows:"", 
    name:"", 
    hint:"" 
    }) 
    */ 
    
Problemi correlati