Модель Ember для json
Я ищу эффективный способ перевода моего объекта Ember в строку json, чтобы использовать его в сообщении websocket ниже
/*
* Model
*/
App.node = Ember.Object.extend({
name: 'theName',
type: 'theType',
value: 'theValue',
})
Метод websocket:
App.io.emit('node', {node: hash});
hash должен быть json-представлением node. {name: thename, type: theType,..}
Для этого должен быть быстрый onliner.. Я не хочу делать это вручную, так как у меня есть много атрибутов, и они могут измениться.
Ответы
Ответ 1
Как указано, вы можете вдохнуть вдохновение из функции 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
, поэтому оператор return функции getJson
выглядит следующим образом:
return this.getProperties(ret);
Ответ 2
Вы можете получить простой объект JS (или хэш) из экземпляра Ember.Object
, вызвав getProperties()
со списком ключей.
Если вы хотите, чтобы это было как строка, вы можете использовать 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"}'
Ответ 3
Я немного изменил решение @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
Я также боролся с этим. Как говорит Мирко, если вы передадите объект ember в JSON.stringify, вы получите круговую опорную ошибку. Однако, если вы храните объект внутри одного свойства и используете 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, которые затем могу выполнить и передать на мой сервер. Я также использую схемы для проверки, так что это решение работает очень хорошо для меня, но если у вас очень большие и динамические модели данных, это невозможно. Я также заинтересован в более простых способах достижения этого.
Ответ 5
Я написал обширную статью о том, как вы можете конвертировать модели ember в собственные объекты или JSON, которые могут помочь вам или другим:)
http://pixelchild.com.au/post/44614363941/how-to-convert-ember-objects-to-json
http://byronsalau.com/blog/convert-ember-objects-to-json/
Ответ 6
Будет ли это работать для вас?
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 с вашей сборкой, вы можете легко объединить эти два объекта так:
$.extend( {}, Ember.getMeta(App.node, 'values'), Ember.getMeta(App.node, 'cache') );
К сожалению, я не нашел способ получить подструктуры, такие как свойства массива таким образом.
Ответ 7
Я модифицировал решение 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 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;
}
});
Я использую эту небольшую настройку, и я доволен ею. Я надеюсь, что это тоже поможет другим!
Благодаря @pangratz и @Kevin-Pauli для их решения!
Ответ 8
Здесь я принимаю @leo, @pangratz и @kevin-pauli решение немного дальше. Теперь он выполняет итерацию не только с массивами, но и через имеет много отношений, он не проверяет, имеет ли значение тип Массив, но вызывает isArray strong > , определенная в Ember API.
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 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;
}
});
Ответ 9
У меня есть:
- исправленный и упрощенный код
- добавлена круговая эталонная профилактика
- добавлено использование get value
-
удалены все свойства по умолчанию пустого компонента
//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:""
})
*/
Ответ 10
У Ember.js появилась библиотека JSON. Я прыгнул в консоль (Firebug) на один пример Todos, и следующее работало для меня:
hash = { test:4 }
JSON.stringify(hash)
Итак, вы должны просто изменить свою линию на
App.io.emit('node', { node:JSON.stringify(hash) })