2012-03-30 9 views
41

C'è un modo per mappare un oggetto dati JSON su un array osservabile e quindi a turno ogni elemento dell'array osservabile essere inizializzato in un tipo di modello di vista specifico?Mappare i dati JSON a Knockout osservabileArray con tipo di vista specifico tipo

Ho guardato tutta la documentazione di eliminazione diretta insieme con gli esempi ad eliminazione diretta e la mappatura qui e non riesco a trovare una risposta che funziona per quello che sto cercando.

Così, ho i seguenti dati JSON:

var data = { 
    state : { 
     name : 'SD', 
     cities : [{ 
      name : 'Sioux Falls', 
      streets : [{ 
       number : 1 
      }, { 
       number : 3 
      }] 
     }, { 
      name : 'Rapid City', 
      streets : [{ 
       number : 2 
      }, { 
       number : 4 
      }] 
     }] 
    } 
}; 

E ho i seguenti vista modelli:

var StateViewModel = function(){ 
    this.name = ko.observable(); 
    this.cities = ko.observableArray([new CityViewModel()]); 
} 

var CityViewModel = function(){ 
    this.name = ko.observable(); 
    this.streets = ko.observableArray([new StreetViewModel()]); 
} 

var StreetViewModel = function(){ 
    this.number = ko.observable(); 
} 

E 'possibile, con la data struttura dei dati e l'utilizzo di plug-in mapping di eliminazione diretta, per far sì che il risultante StateViewModel contenga un ObservableArray popolato con 2 CityViewModels e ogni CityViewModel contenente un observableArray popolato con 2 StreetViewModels?

Attualmente utilizzando il plugin mappatura Sono in grado di farlo per mappare una StateViewModel, ma le 'città' e collezioni 'strade' sono popolati da oggetti generici al posto di istanze della mia città e Via modelli di visualizzazione.

Finiscono con le proprietà osservabili corrette e valori su di loro, non sono solo le istanze dei miei modelli di vista, che è quello che sto cercando.

risposta

68

Scegli questa http://jsfiddle.net/pTEbA/268/

Object.prototype.getName = function() { 
    var funcNameRegex = /function (.{1,})\(/; 
    var results = (funcNameRegex).exec((this).constructor.toString()); 
    return (results && results.length > 1) ? results[1] : ""; 
}; 

function StateViewModel(data){ 
    this.name = ko.observable(); 
    ko.mapping.fromJS(data, mapping, this); 
} 

function CityViewModel(data) { 
    this.name = ko.observable(); 
    ko.mapping.fromJS(data, mapping, this); 
} 

function StreetViewModel(data) { 
    this.name = ko.observable(); 
    ko.mapping.fromJS(data, mapping, this); 
} 

var mapping = { 
    'cities': { 
     create: function(options) { 
      return new CityViewModel(options.data); 
     } 
    }, 
    'streets': { 
     create: function(options) { 
      return new StreetViewModel(options.data); 
     } 
    } 
} 


var data = { state: {name:'SD', cities:[{name:'Sioux Falls',streets:[{number:1},{number:3}]}, 
             {name:'Rapid City',streets:[{number:2},{number:4}]}]}}; 

var vm = new StateViewModel(data.state) 
console.log(vm); 
console.log(vm.getName()); 
console.log(vm.cities()); 
console.log(vm.cities()[0].getName()); 
console.log(vm.cities()[0].streets()); 
console.log(vm.cities()[0].streets()[0].getName()); 
​ 
+1

ho avuto un follow-up domanda però: durante la creazione di 'Le classifiche delle città, sembra che la mappatura' create' in realtà restituisce un singolo oggetto di tipo 'CityViewModel', ed è passato un oggetto di città. Cosa faresti se volessi avere un tipo di raccolta come 'CitiesViewModel' con i propri metodi di raccolta? –

+0

Sembra fantastico? Ma cosa fa il 'this. $ Type = '..Model? Nei costruttori? Non riesco a trovare nulla su una proprietà '$ tipo' nella documentazione Knockout o Knockout.mapping online. – Bart

+0

$ type non è effettivamente necessario ... solo per dimostrare che il costruttore è stato chiamato. – Artem

Problemi correlati