I have a very basic dynamic form in which I am using knockout.js framework. I am able to add or remove contacts as needed in real time. I am having a little difficulty saving the json object inside a textarea. In the function below self.save
takes the values and places them inside a json object. Then the textarea holds attribute data-bind=’value: lastSavedJson’
, which holds the json object. The tricky part that I am struggling is doing this every time keyup, change
is trigger on a input field, checkbox or select menu. Initially this was done with trigger of a button. How can I save the values inside a json object every time a key, checkbox, select menu is triggered? JSFIDDLE
var initialData = [{
firstName: "Jenny",
lastName: "LaRusso",
phone: "(555) 121-2121",
alt_phone: "(555) 123-4567",
main1: false,
main2: true
}, {
firstName: "Sensei",
lastName: "Miyagi",
phone: "(555) 444-2222",
alt_phone: "(555) 999-1212",
main1: true,
main2: false
}];
var ContactsModel = function (contacts) {
var self = this;
self.contacts = ko.observableArray([]);
ko.utils.arrayForEach(contacts, function (contact) {
self.contacts.push({
firstName: contact.firstName,
lastName: contact.lastName,
phone: contact.phone,
alt_phone: contact.alt_phone,
main1: ko.observable(contact.main1),
main2: ko.observable(contact.main2)
});
});
$.getJSON("functions/getPerson.php", function(allData) {
var initialData = $.map(allData, function(person) { return new ContactsModel(person) });
console.log(self.contacts(initialData));
});
self.addContact = function () {
self.contacts.push({
firstName: "",
lastName: "",
phone: "",
alt_phone: "",
main1: false,
main2: false
});
};
self.removeContact = function (contact) {
self.contacts.remove(contact);
};
self.addPhone = function (contact) {
contact.phones.push({
number: ""
});
};
self.removePhone = function (phone) {
$.each(self.contacts(), function () {
this.phones.remove(phone)
})
};
$("input,checkbox,selct").bind('change keyup', function() {
self.save = function () {
self.lastSavedJson(JSON.stringify(ko.toJS(self.contacts), null, 2));
};
});
self.lastSavedJson = ko.observable("");
};
ko.applyBindings(new ContactsModel(initialData));
I made some changes to your viewmodels, so they're laid out a bit nicer. Also, you'll notice I removed the jQUery bit...here's why. 1) In general, if you find yourself using jQuery and referencing the dom inside of a knockout viewmodel, you're doing it wrong / there is a better way to do it idiomatically, the knockout way. This keeps your viewmodel separate from your templates.
2) That would never work the way you wanted it to. Knockout is going to add and remove bits of dom as it sees fit, and jQuery will only bind to events that exist on the page at the moment the query is ran. There is a technique that could work, but knockout actually interferes with event bubbling, which is why reason #1 above is very pertinent. For more info, if you're curious, check out jQuery on and figure out the difference in behavior between
$("input,select").change(changeHandler)
and$("body").on('change','input,select',changeHandler);
and then in your view, get at the mainmodel with a 'with', and wrap just the input in the form you're submitting OR avoid putting names on your template inputs so they don't get submitted with the json data. Also, make sure that you use the valueUpdate binding on your inputs so that it gets serialized immediately.