web-dev-qa-db-fra.com

Ember model to json

Je cherche un moyen efficace de traduire mon objet Ember en une chaîne json, de l'utiliser dans un message websocket ci-dessous

/*
 * Model
 */

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

La méthode websocket:

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

le hachage doit être la représentation JSON du nœud. {name: thename, tapez: theType, ..} Il doit y avoir un onliner rapide pour le faire .. Je ne veux pas le faire manuellement car j'ai beaucoup d'attributs et ils sont susceptibles de changer .. 

21
Stephan

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

Ou si vous avez une propriété ID et souhaitez l'inclure:

App.io.emit('node', {node: node.toJSON({includeId: true})});

0
ecairol

Comme indiqué, vous pouvez vous inspirer de la fonction ember-runtime/lib/core.js # inspect pour obtenir les clés d’un objet, voir 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);
    }
});

Notez que depuis commit 1124005 - qui est disponible dans ember-latest.js et dans la prochaine version, vous pouvez passer le tableau ret directement à getProperties, de sorte que l'instruction de retour de la fonction getJson ressemble à ceci:

return this.getProperties(ret);
14
pangratz

Vous pouvez obtenir un objet JS simple (ou hachage) à partir d'une instance Ember.Object en appelant getProperties() avec une liste de clés.

Si vous le souhaitez sous forme de chaîne, vous pouvez utiliser JSON.stringify().

Par exemple:

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"}'
11
ebryn

J'ai légèrement modifié la solution @pangratz pour lui faire gérer les hiérarchies imbriquées de 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;
    }
});
4
Kevin Pauli

J'ai écrit un article détaillé sur la conversion des modèles de braises en objets natifs ou en JSON, ce qui peut vous aider ou aider d'autres personnes :)

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

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

3
jennas

J'ai aussi eu du mal avec ça. Comme dit Mirko, si vous passez l'objet ember à JSON.stringify, vous obtiendrez une erreur de référence circulaire. Toutefois, si vous stockez l'objet dans une propriété et utilisez stringify sur cet objet, cela fonctionne, même les sous-propriétés imbriquées.

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

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

Toutefois, cela ne fonctionne que dans Chrome, Safari et Firefox. Dans IE8, je reçois un débordement de pile, ce qui n’est pas une solution viable.

J'ai eu recours à la création de schémas JSON sur mes modèles d'objet et écrit une fonction récursive pour effectuer une itération sur les objets à l'aide des propriétés des schémas, puis construire des objets Javascript purs que je peux ensuite hiérarchiser et envoyer à mon serveur. J'utilise également les schémas pour la validation, donc cette solution fonctionne assez bien pour moi, mais si vous avez des modèles de données très volumineux et dynamiques, ce n'est pas possible. Je suis également intéressé par des moyens plus simples pour y parvenir.

3
Georg

Est-ce que cela fonctionnera pour vous?

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

La false est facultative, mais serait plus performante si vous n'avez pas l'intention de modifier les propriétés, ce qui est le cas en fonction de votre question. Cela fonctionne pour moi, mais je me méfie du fait qu'Ember.meta est une méthode privée et peut fonctionner différemment ou même ne pas être disponible dans les prochaines versions. (Bien que ce ne soit pas immédiatement clair pour moi si Ember.getMeta () est privé). Vous pouvez le voir dans sa dernière forme source ici:

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

La propriété values contient uniquement des propriétés "normales". Vous pouvez collecter toutes les propriétés calculées et mises en cache à partir de Ember.meta( App.node, false ).cached. Donc, à condition d'utiliser jQuery avec votre construction, vous pouvez facilement fusionner ces deux objets comme suit:

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

Malheureusement, je n'ai pas trouvé le moyen d'obtenir de cette manière des sous-structures telles que les propriétés de tableau.

2
mkoistinen

J'ai modifié la solution @ Kevin-pauli pour qu'elle fonctionne également avec les tableaux:

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;
    }
});

J'ai également apporté quelques modifications supplémentaires pour obtenir le meilleur des deux mondes. Avec la version suivante, je vérifie si l’objet Jsonable a une propriété spécifique qui m’informe sur laquelle de ses propriétés doit être sérialisée: 

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;
    }
});

J'utilise ce petit Tweak et j'en suis heureux. J'espère que ça va aider les autres aussi!

Merci à @pangratz et @ Kevin-Pauli pour leur solution!

1
Leo

Ici, je prends un peu plus loin la solution @leo, @pangratz et @ kevin-pauli. Maintenant, il itère non seulement avec des tableaux, mais aussi via a beaucoup relations, il ne vérifie pas si une valeur a le type Array mais appelle la fonction isArray définie dans l'API d'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
Klaus

J'ai:

  • code fixe et simplifié
  • prévention de référence circulaire ajoutée
  • utilisation supplémentaire de get of value
  • supprimé toutes les propriétés par défaut d'un composant vide

    //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:""
    })
    */
    
0
Shimon Doodkin