2012-02-08 37 views
10

Passando attraverso la documentazione di Ember.js, non sono in grado di capire come creare modelli annidati. Si supponga che ho il seguente JSON:Come creare modelli nidificati in Ember.js?

App.jsonObject = { 
    id: 1812, 
    name: 'Brokerage Account', 
    positions: [ 
     { 
      symbol: 'AAPL', 
      quantity: '300' 
     }, 
     { 
      symbol: 'GOOG', 
      quantity: '500' 
     } 
    ] 
} 

Se creo un oggetto del modello come questo

App.account = Ember.Object.create(App.jsonObject); 

solo le proprietà di alto livello (id e nome) ottenere legato a modelli, la matrice posizioni nidificati fa non essere legato correttamente Di conseguenza l'aggiunta, l'eliminazione o l'aggiornamento delle posizioni non influisce sul display. Esiste un modo manuale o automatico per trasformare l'array delle posizioni in modo che sia rilegato (simile a ObservableCollection in WPF)?

Ho creato un jsfiddle per sperimentare questo: http://jsfiddle.net/nareshbhatia/357sg/. Come puoi vedere, le modifiche alle proprietà di livello superiore si riflettono nell'output, ma non tutte le modifiche alle posizioni lo sono. Apprezzerei molto ogni suggerimento su come farlo.

Grazie.

Naresh

Edit: La situazione ideale sarebbe se Ember.js potesse in qualche modo di analizzare il mio feed JSON in oggetti Ember.js nidificate. Ad esempio, cosa succede se definisco esplicitamente le mie classi come segue, in modo che aiuti Ember.js a creare gli oggetti giusti?

App.Account = Ember.Object.extend({ 
    id: null, 
    name: null, 
    positions: Ember.ArrayProxy.create() 
}); 

App.Position = Ember.Object.extend({ 
    symbol: null, 
    quantity: null, 
    lastTrade: null 
}); 

App.account = App.Account.create(App.jsonObject); 

Il mio obiettivo finale è quello di visualizzare tale struttura in una griglia gerarchica che può espandersi/compressione a livello di account. Venendo dal mondo WPF/Silverlight, è abbastanza facile fare qualcosa di simile. Tutto quello che devi fare è specificare un modello annidato per la griglia in XAML e sa come interpretare il tuo modello. È possibile trovare un esempio here - non è troppo difficile da seguire. Mi chiedo se qualcosa di simile sia possibile in Ember.js.

+0

Non ho molta familiarità con WPF o con i suoi controlli (non ho funzionato in quasi 4 anni), ma sembra che qualcosa del genere non dovrebbe essere così male da implementare in Ember & Handlebars. –

risposta

5

È necessario utilizzare pushObject non push quando si aggiunge a oggetti di array Ember con collegamenti. E probabilmente dovresti usare get() quando accedi alla proprietà positions. Vedi il mio jsFiddle per le correzioni.

http://jsfiddle.net/ud3323/Y5nG5/

+0

Grazie. Questo è molto utile in quanto mi permette di trattare posizioni come proprietà di prima classe. Tuttavia, non risolve ancora il problema con le proprietà a livello annidato (la linea commentata vicino alla fine del mio violino). Ho modificato la mia domanda per chiarire il mio obiettivo di livello superiore. Sarei davvero interessato alla tua opinione su questo. Grazie ancora. – Naresh

+0

Per un array annidato devi eseguire un'iterazione sull'array e creare oggetti Ember da ognuno di essi. Non penso che ci sia qualcosa di incorporato in Ember che faccia questo per te. –

+0

è sparito questo violino? – Qrilka

1

Ho creato una fabbrica oggetto ricorsivo che potete gradire:

Sarà iterare l'oggetto e creare Ember array o oggetti nidificati, restituendo un albero pieno di oggetti Ember!

Qui è la fonte per il vostro riferimento, e un violino JS: http://jsfiddle.net/SEGwy/2/

Si prega di notare: il violino scrive l'output alla console, in modo da non vedere alcun output sullo schermo.

RecursiveObject = { 

     // http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ 
     TypeOf: function (input) { 
      try { 
       return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); 
      } catch (e) { 
       return typeof input; 
      } 
     }, 

     // Factory method.. 
     create: function (args) { 

      args = args || {}; 
      ctxt = this; 

      switch (this.TypeOf(args)) { 

       // Return an Ember Array 
       case "array": 

        var result = Ember.A(); 

        for (var i = 0; i < args.length; i++) { 
         x = this.create(args[i]); 
         result.push(x); 
        }; 

        break; 

       // Or a recursive object. 
       case "object": 

        var result = Ember.Object.create(); 

        $.each(args, function (key, value) { 

         result.set(key, ctxt.create(value)); 

        }); 

        break; 

       default: 

        // Or just return the args. 
        result = args; 
        break; 

      } 

      return result; 

     } 

    } 

    // Example 

    jsonObject = { 
    id: 1812, 
    name: 'Brokerage Account', 
    positions: [ 
     { 
      symbol: 'AAPL', 
      quantity: '300' 
     }, 
     { 
      symbol: 'GOOG', 
      quantity: '500' 
     } 
    ] 
    } 

    x = RecursiveObject.create(jsonObject); 
    console.log(x); 
0

Ho scritto il mio semplice modello di fabbrica basato sulla soluzione di Alexandros K ma che supporta i moduli ES6.Ho pensato che sarebbe condividere :)

import Ember from 'ember'; 

var ModelFactory = Ember.Object.extend({}); 

ModelFactory.reopenClass({ 
    getType(obj) { 
     if(!obj) { 
      return null; 
     } 

     if(Array === obj.constructor) { 
      return "array"; 
     } 
     else if(typeof obj === "object") { 
      return "object"; 
     } 

     return null; 
    }, 

    // Factory method.. 
    create: function (arg) { 

     const _this = this; 

     switch (this.getType(arg)) { 

      // Return an Ember Array 
      case "array": 

       var newArray = []; 

       arg.forEach(function(item) { 
        newArray.pushObject(_this.create(item)); 
       }); 

       return newArray; 

      // Or a recursive object. 
      case "object": 

       var newObject = Ember.Object.create(); 

       for (var key in arg) { 
        if (arg.hasOwnProperty(key)) { 
         newObject.set(key, this.create(arg[key])); 
        } 
       } 

       return newObject; 

      default: 

       // Or just return the args. 
       return arg; 
     } 
    } 
}); 


export default ModelFactory; 

Usage:

ModelFactory.create(json) 
-1

risposta rilevante per Ember 2.5.0/maggio 2016

avevo una domanda simile (vedi sotto per il mio caso) e era frustrato dai numerosi thread obsoleti/non più utili, quindi sto postando ciò che ho imparato qui nel caso in cui sia utile per gli altri che si imbattono in questa pagina.

TL; DR: Nelle versioni più recenti di Ember è possibile definire il modello estendendo l'oggetto Model in dati ember con gli attributi desiderati. Gli attributi sono definiti chiamando DS.attr(type) (dove il parametro type può essere omesso per passare attraverso qualsiasi tipo desiderato, ad esempio oggetti nidificati dal tuo JSON).

Quindi per questa domanda si potrebbe creare app/models/account (possibilmente utilizzando brace-cli ->ember g resource account):

import Model from 'ember-data/model'; 
import attr from 'ember-data/attr'; 
import { hasMany } from 'ember-data/relationships'; 

export default Model.extend({ 
    name: attr('string'), 
    positions: hasMany('position') 
}); 

e analogamente per app/models/position:

import Model from 'ember-data/model'; 
import attr from 'ember-data/attr'; 

export default Model.extend({ 
    symbol: attr('string'), 
    quantity: attr('number') 
}); 

Il mio caso:

Volevo avere un device associato a connection che potrebbe essere una connessione seriale o TCP, ognuna con opzioni/parametri diversi. In JS pianura, avrei fatto qualcosa di simile:

[{ 
    name: "My serial device", 
    connection: { 
     type: "serial", 
     options: { 
      port: "COM1", 
      baud: 115200, 
      data_bits: 8, 
      parity: "none", 
      stop_bits: 1, 
      flow_control: "none" 
     } 
    } 
}, { 
    name: "My TCP/IP device", 
    connection: { 
     type: "tcp", 
     options: { 
      host: "127.0.0.1", 
      port: 23 
     } 
    } 
}] 

in Ember questo si traduce in un modello device con una proprietà di collegamento il cui tipo è un oggetto (a sinistra non specificato):

import Model from 'ember-data/model'; 
import attr from 'ember-data/attr'; 

export default Model.extend({ 
    name: attr('string'), 
    connection: attr() 
}); 

Se ti stai chiedendo quale sia un buon criterio per determinare se qualcosa dovrebbe essere il suo modello (con la relazione , hasMany, ecc.), una semplice domanda da fare è se la risorsa in questione avrebbe o meno numeri di identificazione associato ad esso. In questo caso, non ha molto senso monitorare le connessioni e i dispositivi separatamente, quindi ho deciso di non creare un modello separato per le connessioni.

Problemi correlati