web-dev-qa-db-ja.com

Ember JSONへのモデル

Emberオブジェクトをjson文字列に変換し、以下のWebSocketメッセージで使用するための効率的な方法を探しています

/*
 * Model
 */

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

Websocketメソッド:

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

ハッシュはノードのjson表現である必要があります。 {name:thename、type:theType、..}これを行うには、高速なオンライン操作が必要です。多くの属性があり、変更される可能性があるため、手動で実行したくありません。

24
Stephan

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

または、IDプロパティがあり、それを含めたい場合:

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

3
ecairol

すでに述べたように、オブジェクトのキーを取得するために ember-runtime/lib/core.js#inspect 関数からインスピレーションを得ることができます。 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);
    }
});

注:commit 1124005 -ember-latest.jsおよび次のリリースで使用可能になるため、ret配列をgetPropertiesに直接渡すことができるため、 getJson関数のreturnステートメントは次のようになります。

return this.getProperties(ret);
14
pangratz

キーのリストを指定してgetProperties()を呼び出すと、_Ember.Object_インスタンスからプレーンなJSオブジェクト(またはハッシュ)を取得できます。

文字列として使いたい場合は、JSON.stringify()を使用できます。

例えば:

_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

@pangratzソリューションを少し変更して、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

私もこれに苦労しています。 Mirkoが言うように、emberオブジェクトをJSON.stringifyに渡すと、循環参照エラーが発生します。ただし、オブジェクトを1つのプロパティ内に格納し、そのオブジェクトでstringifyを使用すると、ネストされたサブプロパティ。

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

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

ただし、これはChrome、Safari、Firefoxでのみ機能します。 IE8ではスタックオーバーフローが発生するため、これは実行可能なソリューションではありません。

オブジェクトモデルでJSONスキーマを作成し、スキーマのプロパティを使用してオブジェクトを反復処理する再帰関数を記述し、次に文字列化してサーバーに送信できる純粋なJavascriptオブジェクトを作成しました。私は検証にもスキーマを使用しているため、このソリューションはかなりうまく機能しますが、非常に大規模で動的なデータモデルがある場合、これは不可能です。これを達成するためのより簡単な方法にも興味があります。

4
Georg

これでうまくいきますか?

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

falseはオプションですが、プロパティを変更するつもりがない場合はパフォーマンスが向上します。これは、質問のとおりです。これは私にとってはうまくいきますが、Ember.metaはプライベートメソッドであり、異なる動作をするか、将来のリリースで使用できなくなる可能性があることに注意します。 (ただし、Ember.getMeta()がプライベートかどうかはすぐにはわかりません)。あなたはここで最新のソース形式でそれを見ることができます:

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

valuesプロパティには、「通常」のプロパティのみが含まれます。 Ember.meta( App.node, false ).cachedから、キャッシュされた計算済みプロパティを収集できます。したがって、ビルドでjQueryを使用すると、次のようにこれら2つのオブジェクトを簡単にマージできます。

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

悲しいことに、この方法で配列プロパティのようなサブ構造を取得する方法が見つかりませんでした。

2
mkoistinen

emberモデルをネイティブオブジェクトまたはJSONに変換する方法に関する広範な記事を作成しました。

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

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

2
jennas

@ Kevin-pauliソリューションを変更して、配列でも機能するようにしました。

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

また、両方の世界を最大限に活用するために、さらに変更を加えました。次のバージョンでは、Jsonableオブジェクトに、シリアル化する必要があるプロパティを通知する特定のプロパティがあるかどうかを確認します。

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

この小さなTweakを使用していますが、満足しています。他の人にも役立つことを願っています!

解決策を提供してくれた@pangratzと@ Kevin-Pauliに感謝します。

1
Leo

ここで、@ leo、@ pangratz、および@ kevin-pauliのソリューションを少し進めます。配列だけでなくhas many関係も反復処理するようになり、値がArrayしかし、EmberのAPIで定義されているisArray関数を呼び出します。

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

私が持っています:

  • 修正および簡略化されたコード
  • 循環参照防止を追加
  • 値の取得の追加の使用
  • 空のコンポーネントのすべてのデフォルトプロパティを削除

    //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