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、..}これを行うには、高速なオンライン操作が必要です。多くの属性があり、変更される可能性があるため、手動で実行したくありません。
App.io.emit('node', {node: node.toJSON()});
または、IDプロパティがあり、それを含めたい場合:
App.io.emit('node', {node: node.toJSON({includeId: true})});
すでに述べたように、オブジェクトのキーを取得するために 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);
キーのリストを指定して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"}'
_
@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;
}
});
私もこれに苦労しています。 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オブジェクトを作成しました。私は検証にもスキーマを使用しているため、このソリューションはかなりうまく機能しますが、非常に大規模で動的なデータモデルがある場合、これは不可能です。これを達成するためのより簡単な方法にも興味があります。
これでうまくいきますか?
_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') );
_
悲しいことに、この方法で配列プロパティのようなサブ構造を取得する方法が見つかりませんでした。
emberモデルをネイティブオブジェクトまたはJSONに変換する方法に関する広範な記事を作成しました。
http://pixelchild.com.au/post/44614363941/how-to-convert-ember-objects-to-json
@ 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に感謝します。
ここで、@ 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;
}
});
私が持っています:
空のコンポーネントのすべてのデフォルトプロパティを削除
//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:""
})
*/