I'm fairly new to knockout and am struggling with how to update a portion of my view model. I have a WCF api that returns a JSON string containing a company name and a list of divisions. Within each division, it can contain multiple addresses and contacts. Each contact can also have multiple addresses. I am using ko.mapping to map the data to my view model, which as I understand it, creates observables for all the properties. I can display the data correctly using nested foreach loops as seen in the link/code below.
My problem is when the edit link is clicked. I'm using ko.dataFor(this), which is return my entire view model. How would I go about getting the specific address or contact that was clicked?
Javascript
$(function () {
$("#addressDialog").hide();
$("#contactDialog").hide();
var data = {
"CompanyID": 3,
"CompanyName": "Company #1",
"CompanyDivisions": [{
"Addresses": [{
"Address1": "1234 Broadway",
"Address2": null,
"AddressID": 51135,
"AddressType": {
"AddressTypeID": 1,
"Description": "Mailing"
},
"City": "My City",
"ContactID": 0,
"Owner": null,
"State": {
"StateCode": "IL",
"StateID": 1,
"StateName": "Illinois"
},
"Zip": "61234",
"ZipPlus4": "1111"
}],
"Contacts": [{
"Addresses": [],
"ContactID": 8,
"ContactType": {
"ContactTypeID": 5,
"Description": "Supervisor"
},
"CompanyID": 3,
"FirstName": "John",
"LastName": "Doe",
"MiddleName": ""
}],
"Division": {
"Description": "Customer Service",
"DivisionCode": "CS",
"DivisionID": 1
},
"XrefID": 87173
}, {
"Addresses": [{
"Address1": "1234 Broadway",
"Address2": "Dock #2",
"AddressID": 51134,
"AddressType": {
"AddressTypeID": 2,
"Description": "Delivery"
},
"City": "My City",
"ContactID": 0,
"CompanyID": 3,
"State": {
"StateCode": "IL",
"StateID": 1,
"StateName": "Illinois"
},
"Zip": "61234",
"ZipPlus4": "3050"
}],
"Contacts": [{
"Addresses": [],
"ContactID": 9,
"ContactType": {
"ContactTypeID": 9,
"Description": "Executive Director"
},
"CompanyID": 3,
"FirstName": "Jane",
"LastName": "Doe",
"MiddleName": ""
}, {
"Addresses": [],
"ContactID": 16,
"ContactType": {
"ContactTypeID": 13,
"Description": "Book Keeper"
},
"CompanyID": 3,
"FirstName": "Tony",
"LastName": "Adams",
"MiddleName": null
}, {
"Addresses": [{
"Address1": "1234 Broadway",
"Address2": null,
"AddressID": 51950,
"AddressType": {
"AddressTypeID": 2,
"Description": "Delivery"
},
"City": "My City",
"ContactID": 17,
"CompanyID": 3,
"State": {
"StateCode": "IL",
"StateID": 1,
"StateName": "Illinois"
},
"Zip": "61234",
"ZipPlus4": null
}],
"ContactID": 17,
"ContactType": {
"ContactTypeID": 10,
"Description": "CFO"
},
"CompanyID": 3,
"FirstName": "Milton",
"LastName": "Freemon",
"MiddleName": null
}],
"Division": {
"Description": "Accouting",
"DivisionCode": "AC",
"DivisionID": 4
},
"XrefID": 128438
}, {
"Addresses": [{
"Address1": "1234 Broadway",
"Address2": null,
"AddressID": 51133,
"AddressType": {
"AddressTypeID": 2,
"Description": "Delivery"
},
"City": "My City",
"State": {
"StateCode": "IL",
"StateID": 1,
"StateName": "Illinois"
},
"Zip": "61234",
"ZipPlus4": "3050"
}],
"Contacts": [{
"Addresses": [],
"ContactID": 10,
"ContactType": {
"ContactTypeID": 13,
"Description": "Programmer"
},
"FirstName": "Jill",
"LastName": "Doe",
"MiddleName": null
}, {
"Addresses": [],
"ContactID": 13,
"ContactType": {
"ContactTypeID": 7,
"Description": "Network Engineer"
},
"FirstName": "Matt",
"LastName": "Williams",
"MiddleName": null
}],
"Division": {
"Description": "Information Technology",
"DivisionCode": "IT",
"DivisionID": 2
},
"XrefID": 133320
}]
};
var viewModel = {
company: ko.mapping.fromJS(data),
selectedAddress: ko.observable(),
selectedContact: ko.observable(),
selectAddress: function () {
viewModel.selectedAddress(this);
},
selectContact: function () {
viewModel.selectedContact(this);
},
}
ko.applyBindings(viewModel);
createTabs();
$(".address-edit").on("click", function () {
viewModel.selectAddress(ko.dataFor(this));
$("#addressDialog").dialog({
buttons: {
Save: function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
$(".contact-edit").on("click", function () {
viewModel.selectContact(ko.dataFor(this));
$("#contactDialog").dialog({
buttons: {
Save: function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
});
function createTabs() {
$("#tabs").tabs();
};
HTML
<div id="tabs" class="ui-tabs">
<div data-bind="with: company">
<h1 data-bind="text: CompanyName"></h1>
<ul data-bind="foreach: CompanyDivisions">
<li> <a data-bind="attr: { href: '#' + Division.DivisionCode(), title: Division.DivisionCode}, text: Division.DivisionCode">
<span data-bind="text: Division.DivisionCode"></span></a>
</li>
</ul>
<div data-bind="foreach: CompanyDivisions">
<div data-bind="attr: {id: Division.DivisionCode()}">
<h2 data-bind="text: Division.Description"></h2>
<h3>Addresses</h3>
<div data-bind="foreach: Addresses">
<div class="ui-widget ui-widget-content ui-corner-all box"> <b><span data-bind="text: AddressType.Description"></span></b>
<a href="#" class="address-edit">Edit</a>| <a href="#" class="address-delete">Delete</a>
<br /> <span data-bind="text: Address1"></span>
<br /> <span data-bind="text: City"></span>, <span data-bind="text: State.StateCode"></span>
<span data-bind="text: Zip"></span>- <span data-bind="text: ZipPlus4"></span>
</div>
</div>
<br />
<div style="clear:both"></div>
<h3>Contacts</h3>
<div data-bind="foreach: Contacts">
<div class="ui-widget ui-widget-content ui-corner-all box"> <b><span data-bind="text: ContactType.Description"></span></b>
<a href="#" class="contact-edit">Edit</a>| <a href="#" class="contact-delete">Delete</a>
<br /> <span data-bind="text: LastName"></span>, <span data-bind="text: FirstName"></span>
<span data-bind="text: MiddleName"></span>
<br />
<div data-bind="foreach: Addresses">
<br /> <b><span data-bind="text: AddressType.Description"></span></b>
<br /> <span data-bind="text: Address1"></span>
<br /> <span data-bind="text: City"></span>, <span data-bind="text: State.StateCode"></span>
<span data-bind="text: Zip"></span>- <span data-bind="text: ZipPlus4"></span>
</div>
</div>
</div>
<div style="clear:both"></div>
</div>
</div>
</div>
</div>
<div id="addressDialog" data-bind="with: selectedAddress">Address :
<input type="text" data-bind="value: Address1" />
<br />City :
<input type="text" data-bind="value: City" />
<br />Zip :
<input type="text" data-bind="value: Zip" />
<br />
</div>
<div id="contactDialog" data-bind="with: selectedContact">First :
<input type="text" data-bind="value: FirstName" />
<br />Middle :
<input type="text" data-bind="value: MiddleName" />
<br />Last :
<input type="text" data-bind="value: LastName" />
<br />
</div>
Thanks in advance for your assistance,
Greg
I have updated your view model little bit and remove the jquery on click binding instead of this have used knockout click binding.
var viewModel = {
company: ko.mapping.fromJS(data),
selectedAddress: ko.observable(),
selectedContact: ko.observable(),
selectAddress: function () {
viewModel.selectedAddress(this);
},
selectContact: function () {
viewModel.selectedContact(this);
},
edit: function (d) {
viewModel.selectedAddress(d);
$("#addressDialog").dialog({
buttons: {
Save: function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
},
contactedit: function (d) {
viewModel.selectedContact(d);
$("#contactDialog").dialog({
buttons: {
Save: function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
}
}
ko.applyBindings(viewModel);
html
<a href="#" data-bind="click: $root.edit" class="address-edit">Edit</a>
<a href="#" data-bind="click: $root.contactedit" class="contact-edit">Edit</a>