Подтвердить что ты не робот

Модель 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.. Я не хочу делать это вручную, так как у меня есть много атрибутов, и они могут измениться.

4b9b3361

Ответ 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, которые затем могу выполнить и передать на мой сервер. Я также использую схемы для проверки, так что это решение работает очень хорошо для меня, но если у вас очень большие и динамические модели данных, это невозможно. Я также заинтересован в более простых способах достижения этого.

Ответ 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) })