2012-03-30 4 views
41

Czy istnieje sposób odwzorowania obiektu danych JSON na tablicę obserwowalną, a następnie z kolei każda pozycja tablicy obserwowalnej zostanie zainicjowana na określony typ modelu widoku?Odwzorowuj dane JSON na Nook do obserwowaniaArray z określonym typem widoku widoku

Przyjrzałem się całej dokumentacji nokautu wraz z przykładami nokautu i mapowania tutaj i nie mogę znaleźć żadnej odpowiedzi, która działa na to, czego szukam.

Więc mam następujące dane JSON:

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

I mam następujące modele wyświetlania:

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

Czy to możliwe, przy danej struktury danych i za pomocą wtyczki mapowania nokaut, w mieć wynik StateViewModel zawierać observableArray wypełnione 2 CityViewModels, a każdy CityViewModel zawierający observableArray wypełnione 2 StreetViewModels?

Obecnie za pomocą wtyczki mapowania mogę go zmapować do StateViewModel, ale kolekcje "miast" i "ulic" są wypełnione obiektami ogólnymi, a nie instancjami modeli widoku Miasto i Ulica.

Kończą się właściwymi obserwowalnymi właściwościami i wartościami na nich, po prostu nie są instancjami moich modeli widokowych, po to właśnie jestem.

Odpowiedz

68

Sprawdź to 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

ja miałem jeden śledzić pytanie jednak: podczas tworzenia 'cities', wygląda na to, że' mapping create' faktycznie zwraca pojedynczy obiekt typu 'CityViewModel' i jest przekazywana obiekt miejski. Co byś zrobił, gdybyś chciał mieć typ kolekcji podobny do 'CitiesViewModel' z własnymi metodami zbierania? –

+0

Wygląda świetnie? Ale co robi 'this. $ Type = '..Model' w konstruktorach? Nie mogę znaleźć niczego na temat właściwości '$ type' w dokumentacji Knockout lub Knockout.mapping. – Bart

+0

Typ $ nie jest faktycznie potrzebny ... tylko po to, aby pokazać, że konstruktor został wywołany. – Artem