I have a model for a projects view which is very simple. There is a click handler for editing a projects which should load the project data from the server into the model. The click handler is called editProject. All I want is to load my observables from the server. This method from inside the models did not work.
this.editProject = function(){
$.getJSON("/projects/get_by_id", {
id: "7"
}).done(function(data){
ko.mapping.fromJSON(data[0], self);
});
};
I'm not sure what went wrong because you haven't shown your view or whole view model. How are you initializing your viewmodel before editProject
is called?
Here's an example with the editProject
method in a layer above the actual project
.
ko.mapping.toJS
on a plain object (from the server)ko.mapping.fromJS(data, project)
. If data
contains new properties, those won't be available at the time of ko.applyBindings
, and therefore won't be data-bound.
const $ = fakeJQuery();
// The project should have its own viewmodel with initial data
// probably received from the server during first load
const myProjects =[
ko.mapping.fromJS({ id: "1", additionalInfo: null }),
ko.mapping.fromJS({ id: "7", additionalInfo: null })
];
const ViewModel = function() {
this.projects = ko.observableArray(
myProjects
);
// Take the project to edit as an argument
this.editProject = function(project) {
$.getJSON("/projects/get_by_id", project)
.done(function(data) {
// Because we have access to the clicked project,
// we map to its existing viewmodel using `fromJS`
ko.mapping.fromJS(data, project);
});
};
};
ko.applyBindings(new ViewModel());
// Mocks
function fakeJQuery() {
return {
// Mock ajax request
getJSON: function(url, opts) {
let done = () => true;
setTimeout(function() {
// Test data to indicate an update:
done({
id: opts.id(),
additionalInfo: "Test " + opts.id()
});
}, 1000);
return {
done: cb => done = cb
};
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<ul data-bind="foreach: projects">
<li>
<code data-bind="text: 'id: ' + id()"></code>
<button data-bind="click: $parent.editProject">edit</button>
<p>
Info:
<strong data-bind="text: additionalInfo"></strong>
<em data-bind="visible: !additionalInfo()">not loaded</em>
</p>
</li>
</ul>