I'm having an issue with knockout.js and the mapping plugin not creating models for child arrays in the source data
var data = {
outer: [
{
'id': 1,
name: 'test outer',
inner: [{
'id': 1,
name: 'test inner'}]}]
};
function OuterModel(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
self.fullText = ko.computed(function() {
return self.id() + ". " + self.name();
});
}
function InnerModel(data, parent) {
var self = this;
ko.mapping.fromJS(data, {}, this);
self.fullText = ko.computed(function() {
return self.id() + ". " + self.name() + "(" + parent + ")";
});
}
function PageModel() {
var self = this;
this.data = null;
}
var mapping = {
'outer': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
var thisModel = new OuterModel(options.data);
return thisModel;
}
},
'inner': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
var thisModel = new InnerModel(options.data);
return thisModel;
}
}
};
var model = new PageModel();
model.data = ko.mapping.fromJS(data, mapping);
(This is a small of a repo I can make for this. Fiddle available here: http://jsfiddle.net/msieker/6Wx3s/)
In short, the InnerModel constructor is never called. I've tried this with the 'InnerModel'
both where it is in this snippet, and within the 'inner'
mapping. From most accounts of what I've seen, this should just work, but obviously I'm missing something.
Anyone have experience with this that can point me in the right direction?
EDIT: Based on @John Earles answer, I've gotten this a bit closer to what I need:
var data = {
outer: [
{
'id': 1,
name: 'test outer',
inner: [{
'id': 1,
name: 'test inner'}]}]
};
var outerMapping = {
'outer': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
var thisModel = new OuterModel(options.data);
return thisModel;
}
}
};
function OuterModel(data) {
var self = this;
ko.mapping.fromJS(data, innerMapping, this);
self.fullText = ko.computed(function() {
return self.id() + ". " + self.name();
});
}
var innerMapping = {
'inner': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
console.log(options);
var thisModel = new InnerModel(options.data, options.parent());
return thisModel;
}
}
};
function InnerModel(data, parent) {
var self = this;
ko.mapping.fromJS(data, {}, this);
self.fullText = ko.computed(function() {
return self.id() + ". " + self.name() + "(" + parent + ")";
});
}
function PageModel() {
var self = this;
this.data = null;
}
var model = new PageModel();
model.data = ko.mapping.fromJS(data, outerMapping);
ko.applyBindings(model);?
However, the parent
that gets passed to InnerModel is null
, which getting that is the whole reason I'm pursuing the mapping plugin. The docs lead me to believe that this should be getting getting passed in on the options
parameter to the create
function, but instead I get an observable
whose value is null
. Any additional pointers in this direction?
You are not passing your mapping options (which defines how to map inner) into the OuterModel mapping call.
function OuterModel(data) {
var self = this;
ko.mapping.fromJS(data, mapping, this);
self.fullText = ko.computed(function() {
return self.id() + ". " + self.name();
});
}
EDIT: Updated fiddle to show manual attachment of parent:
http://jsfiddle.net/jearles/6Wx3s/5/
I had a very similar scenario a while back, check out the Q & A here: Map JSON data to Knockout observableArray with specific view model type
In my example I have a StateViewModel which contains an observableArray populated with 2 CityViewModels, and each CityViewModel contains an observableArray populated with 2 StreetViewModels.
I then wanted this view model structure to be constructed from my hierarchical json data using knockout's mapping plugin.
This fiddle maps out the answer: http://jsfiddle.net/KodeKreachor/pTEbA/2/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With