2011-12-29 136 views
21

我正在尋找一種有效的方式,以我的灰燼對象轉換成JSON字符串,在WebSocket的消息,使用下面灰燼模型JSON

/* 
* Model 
*/ 

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

WebSocket的方法:

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

哈希應該是節點的json表示。 {name:thename,type:theType,..} 必須有一個快速的在線人做到這一點..我不想這樣做manualy,因爲我有很多屬性,他們很可能會改變..

回答

14

如前所述,你可以採取的靈感來自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); 
    } 
}); 

注意,因爲犯1124005 - 它可在ember-latest.js並在下一版本 - 你可以直接傳遞ret陣列getProperties,所以getJson函數的返回語句如下所示:

return this.getProperties(ret); 
+0

這工作在IE8中,我不得不添加另一個監護人,如果:(key.indexOf('__ ember')!== -1){ continue; } – rallrall 2013-04-08 14:18:00

+2

這似乎不支持Jsonables的嵌套層次結構 – 2013-04-11 19:43:07

-3

Ember。 js似乎有一個JSON庫可用。我跳進一個在託多斯例如控制檯(螢火蟲)和我下面的工作:

hash = { test:4 } 
JSON.stringify(hash) 

所以,你應該能夠只是改變你的行

App.io.emit('node', { node:JSON.stringify(hash) }) 
+2

我認爲史蒂芬挑戰在於獲得的散列表示可再傳遞給JSON.stringify。傳遞實際的Ember對象不起作用(我收到關於循環結構的錯誤)。通過Ember來源挖掘,我無法找到將Ember對象轉換爲散列的內置方式,因此您可能需要爲您的對象手動實現此操作。 – 2011-12-30 18:05:31

+0

@MirkoFroehlich - 啊,呃。我想我匆匆讀過它:-) – 2012-01-03 13:53:45

11

你可以得到一個簡單的通過調用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"}' 
+1

如果你想從Ember模型中獲得所有屬性,該怎麼辦? obj.getProperties()不起作用。是否有任何簡單的方法,而不是列出所有屬性。如果模型中有太多屬性,那將是單調乏味的。 – Rajat 2012-03-16 03:25:32

+0

除了使用'Object.keys'從Ember對象中提取所有屬性外,沒有其他辦法。你必須知道你使用的是什麼屬性。 – ebryn 2012-03-21 04:59:06

+1

你可以從'Ember.inspect'獲取一些靈感,參見https://github.com/emberjs/ember.js/blob/master/packages/ember-runtime/lib/core.js#L290-308 – pangratz 2012-04-17 21:11:38

3

我也一直在掙扎與此有關。正如Mirko所說,如果你將這個燼對象傳遞給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對象,然後我可以將它們串化併發送到我的服務器。我也使用模式進行驗證,所以這個解決方案對我來說工作得很好,但如果你有非常大的動態數據模型,這是不可能的。我也對更簡單的方法感興趣。

2

這項工作適合你嗎?

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

可悲的是,我還沒有找到一種方式來獲得子結構,如以這種方式陣列屬性。

3

我已經寫了關於如何燼模型轉換爲本地對象或JSON它可以幫助你或他人:)

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

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

+0

此鏈接不起作用 – 2013-04-11 19:27:06

+0

站點備份@KevinPauli - 我的DNS在一段時間內令人討厭。 – jennas 2013-04-16 00:21:23

+0

啊好的。編輯帖子,以便我可以撤消我的downvote。那天我肯定心情很糟糕,對不起 – 2013-04-17 01:29:38

4

上的文章我體改@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; 
    } 
}); 
1

我修改@凱文 - 保利的解決方案,使之與陣列的作品,以及:

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

我使用這個小的調整,我很高興。我希望它能幫助別人!

感謝@pangratz和@ Kevin-Pauli的解答!

1

在這裏,我將@leo,@pangratz和@ kevin-pauli解決方案向前邁了一步。現在它不僅在數組中迭代,而且通過有很多關係,它不會檢查值是否具有類型數組,但它會調用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

在json前添加「var」。提出了一項改變 – 2015-11-04 22:38:43

0

我有:

  • 固定和簡化的代碼
  • 添加循環引用預防
  • 增加利用價值獲取的
  • 刪除了所有的空組件的默認屬性的

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