I have the following Knockout viewmodel:
var myViewModel = {
courseData: ko.observable(null);
};
I then receive the following data from the server:
var data = {
"courses": [
{
"srcCourses": [ { "code": "001", "name": "Course 1"}, { "code": "002", "name": "Course 2"} ],
"destCourse": { "code": "003", "name": "Course 3"}
},
{
"srcCourse": [ { "code": "004", "name": "Course 4"}, { "code": "005", "name": "Course 5"} ],
"destCourse": { "code": "006", "name": "Course 6"}
}
]
}
I run is through the Knockout mapping plugin into my view model as follows:
this.courseData(ko.mapping.fromJS(data));
This essentially leaves me with the following view model object hierarchy:
{
KnockoutObservable(this.courseData): {
KnockoutObservableArray(Courses): [
{
KnockoutObservableArray(srcCourses): [ ... ],
destCourse: { KnockoutObservable(code), KnockoutObservable(name) }
},
{
...
}
]
}
}
The problem is that the "destCourse" object remains an object and does not get converted to observable (although every property within the destCourse object gets converted to observable).
How can I make all child objects the data be converted to observable too? Ideally in the most generic way possible?
I've come across this before and I've never been able to work out why knockout does this with child objects.
Anyway, you just need to give the mapper a bit of guidance as described in the docs
var coursesMapping = {
"destCourse":{
create:function(options){
return ko.observable(ko.mapping.fromJS(options.data));
}
}
}
var mapped = ko.mapping.fromJS(data, coursesMapping);
Here's a snippet:
var data = {
"courses": [
{
"srcCourses": [ { "code": "001", "name": "Course 1"}, { "code": "002", "name": "Course 2"} ],
"destCourse": { "code": "003", "name": "Course 3"}
},
{
"srcCourse": [ { "code": "004", "name": "Course 4"}, { "code": "005", "name": "Course 5"} ],
"destCourse": { "code": "006", "name": "Course 6"}
}
]
}
var coursesMapping = {
"destCourse":{
create:function(options){
return ko.observable(ko.mapping.fromJS(options.data));
}
}
}
var mapped = ko.mapping.fromJS(data,coursesMapping);
console.log(mapped.courses()[0].destCourse().name()); // "Course 3"
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>