In my application, Iam having a table binded by calling Web Api service.
I have written code to display the selected row when a particular row is selected and it works fine.
Now, I want to show a selected row by default once the web api method returned success message.
How should i call 'SelectConfig' inside success method. When I tried it returns nothing. Please help me to get out of these problem.
My HTML:
<tbody data-bind="foreach: datas">
<tr>
<td style="vertical-align: middle;">
<asp:CheckBox ID="chkChild" runat="server" />
</td>
<td style="vertical-align: middle;">
<a id="aTag" data-bind="text: (Name().length > 20 ? Name().substring(0, 20) + '....' : Name()), value: ID, click: $parent.SelectConfig"></a>
</td>
<td style="vertical-align: middle;" data-bind="text: Type == '' || Type == null || Type == undefined ? '--' : Type"></td>
</tr>
</tbody>
<div data-bind="with: Selected, visible: isVisibleDetails">
<div class="col-md-8 value" data-bind="text: (Name() == '' || Name() == null || Name() == undefined) ? '--' : Name">
<select id="ddlType_E" data-bind="options: $root.ddlTypes, optionsText: 'Type', optionsValue: 'ID', optionsCaption: 'Select..', value: selectedTypeId" class="form-control"></select>
</div>
My View Model:
<script type="text/javascript">
function oppConfig(ID, Name,TypeID) {
this.ID = ko.observable(ID);
this.Name = ko.observable(Name);
this.selectedTypeId = ko.observable(TypeID);
}
function ViewModel() {
var self = this;
this.datas= ko.observableArray([]);
getdatas();
this.ddlTypes = ko.observableArray([]);
getOppType();
}
this.Selected = ko.observable(this.datas()[0]);
//selectItem
this.SelectConfig = function (oppConfig) {
alert(ko.toJSON(oppConfig));
self.Selected(oppConfig);
}
function datas() {
$.ajax({
type: "GET",
url: '---',
dataType: "json",
cache: false,
crossDomain: true,
processData: true,
success: function (data) {
self.datas.destroyAll();
if (data.length > 0) {
$.each(data, function (index) {
self.datas.push(new oppConfig(data[index].ID, data[index].Name, data[index].Type));
});
//Here, I want the to call the select config
}
else {
}
},
error: function (data) {
}
});
}
ko.applyBindings(new ViewModel());
</script>
You need to include the data-binding to the <tr> element in your HTML markup. Right now, you have the display div for what is selected, but not the selected value itself.
<tbody data-bind="foreach: model.datas">
<tr data-bind="click: $root.selectThing, css: { selected: isSelected} ">
Then in your view model, add a function to return the selected thing:
Also add an observable for the object itself.
function ViewModel() {
var self = this;
this.datas= ko.observableArray([0]);
getdatas();
this.ddlTypes = ko.observableArray([]);
getOppType();
self.CurrentDisplayThing = ko.observable();
self.selectThing = function(item){
self.model.CurrentSelected = ko.observable();
}
}
Finally, in your object representing your config class, add an isSelected variable, which is a knockout function.
function oppConfig(ID, Name,TypeID) {
this.ID = ko.observable(ID);
this.Name = ko.observable(Name);
this.selectedTypeId = ko.observable(TypeID);
self.isSelected = ko.computed(function(){
return selected() === self;
}
}
Some CSS to display your selection:
.selected { background-color: yellow; }
thead tr {
border:1px solid black;
background:lightgray;
}
tbody tr {
border:1px solid black;
cursor: pointer;
}
Related
A have template:
<table data-bind="foreach: {data: messages, as: 'message'}">
<tr> <td data-bind="text: $root.go"></td> </tr>
</table>
My js:
function CreateViewModel() {
var self = this;
this.go = ko.computed(function() {
return 'not really important what here for now';
});
}
ko.applyBindings( new MessagesVM );
The context in 'go' while runtime is 'window', I want it to be the current item.
Is it possible?
If I change tmpl line to "<td data-bind="text: go"></td>" I will have an error ['go' is not defined].
The context in 'go' while runtime is 'window', I want it to be the current item. Is it possible?
I don't think you can with a computed, no. If you make it a simple function you can: data-bind="text: $root.go.call(message)" (generically it would be .call($data), but since you're naming it in your foreach):
function MessagesVM() {
var self = this;
this.messages = ko.observableArray([
"Message 1",
"Message 2"
]);
this.go = function() {
return 'this is: "' + this + '"';
};
}
ko.applyBindings(new MessagesVM);
<table data-bind="foreach: {data: messages, as: 'message'}">
<tr>
<td data-bind="text: $root.go.call(message)"></td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
Alternately, if you want some of the functionality of a computed but acting on the individual item, I'd probably use a binding handler:
ko.bindingHandlers.specialText = {
update: function(element, valueAccessor) {
var value = ko.unwrap(valueAccessor());
element.innerHTML = "'value' is " + value;
}
};
function MessagesVM() {
var self = this;
this.messages = ko.observableArray([
"Message 1",
"Message 2"
]);
}
ko.applyBindings(new MessagesVM);
<table data-bind="foreach: {data: messages, as: 'message'}">
<tr>
<td data-bind="specialText: message"></td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
Turn it into a function and pass the context in. As a computed, it has a cached value and so cannot be context-dependent.
function CreateViewModel() {
var self = this;
this.messages = [
'one',
'two'
];
this.go = function(data) {
var context = data;
return 'Context:' + context;
};
}
ko.applyBindings(new CreateViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<table data-bind="foreach: {data: messages, as: 'message'}">
<tr>
<td data-bind="text: $root.go(message)"></td>
</tr>
</table>
I am trying to access a jQuery Object, which happens to be an input text box to do some validations and adding date picker but unfortunately I am unable to do so.
I am working with KnockoutJS.
I wanted to access the 'input' and call datepicker() on it if 'Datatype' happens to be a 'Date' or a 'Datetime'. But whenever I try to search using .closest('td').next('td').html(), I get a null (from inside the custom bind). Trying this so that I can call the datetimepicker constructor on the input based on the datatype 'td'.
Below is the fiddle that I am trying to work with
JsFiddle: http://jsfiddle.net/sourabhtewari/nkkt88v2/2/
var format = function (str, col) {
col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);
return str.replace(/\{\{|\}\}|\{(\w+)\}/g, function (m, n) {
if (m == "{{") {
return "{";
}
if (m == "}}") {
return "}";
}
return col[n];
});
};
var data = ko.observableArray([{
paramKey: ko.observable('keyName'),
paramValue: ko.observable('Test1'),
dataType: ko.observable('Date')
}]);
var ParamConstr = function (key, value, dataType) {
return {
ParamKey: ko.observable(key),
ParamValue: ko.observable(value),
DataType: ko.observable(dataType)
};
};
var my = my || {};
function Generator() { };
Generator.prototype.rand = Math.floor(Math.random() * 26) + Date.now();
Generator.prototype.getId = function () {
return this.rand++;
};
var idGen = new Generator();
//var ParamData = ko.observableArray([]);
my.viewModel = {
ParamData : ko.observableArray([]),
addParam: function () {
this.ParamData.push(new ParamConstr("$$" + "key1", "value1","Date"));
}};
ko.bindingHandlers.hidden = {
update: function (element, valueAccessor) {
ko.bindingHandlers.visible.update(element, function () { return !ko.utils.unwrapObservable(valueAccessor()); });
}
};
ko.bindingHandlers.clickToEdit = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
var observable = valueAccessor(),
link = document.createElement("a"),
input = document.createElement("input");
var id = idGen.getId();
input.setAttribute("id", id);
element.appendChild(link);
element.appendChild(input);
console.log(document.getElementById(id).id);
var dataType = $(format("#{0}", id)).parent().next('td').html();
//.parent().next().html();
//.closest('td').next('td').html().toString();
console.log(dataType);
switch ($(format("#{0}", id)).parent().next('td').html()) {
case "Datetime":
$(format("#{0}", id)).datetimepicker();
break;
case "Date":
$(format("#{0}", id)).datetimepicker({
timepicker: false,
format: 'Y/m/d'
});
break;
}
observable.editing = ko.observable(false);
ko.applyBindingsToNode(link, {
text: observable,
hidden: observable.editing,
click: observable.editing.bind(null, true)
});
ko.applyBindingsToNode(input, {
value: observable,
visible: observable.editing,
hasfocus: observable.editing,
event: {
keyup: function (data, event) {
//if user hits enter, set editing to false, which makes field lose focus
if (event.keyCode === 13) {
input.blur();
observable.editing(false);
return false;
}
//if user hits escape, push the current observable value back to the field, then set editing to false
else if (event.keyCode === 27) {
observable.valueHasMutated();
observable.editing(false);
return false;
}
}
}
});
}
};
ko.applyBindings(my.viewModel);
html:
<div>
<button id="InputSubmitBtn" type="submit" class="btn btn-custom" data-bind="click: addParam"><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
</div>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Data type</th>
</tr>
</thead>
<tbody data-bind="foreach: ParamData">
<tr>
<td data-bind="text: ParamKey" style="width: 20%"></td>
<td data-bind="clickToEdit: ParamValue" data-text="" style="width: 20%"></td>
<td data-bind="text: DataType" style="width: 20%"></td>
</tr>
</tbody>
</table>
Any help as to how I can fix this would be great!
So it seems you got an answer from G_S.
If anyone is wondering what was the right selector, var dataType = $(element).next().text(); does the job perfectly. You couldn't access any data because at the time of the call, it wasn't there yet. You could try var dataType = $(element).prev().text(); and see that you can retrieve $$key1.
Fiddle
Anyway, as you got answered, I didn't dig further on how to resolve this, have a good day :)
I have a table which has four columns namely Code, Name, Quantity and Price. Out of these, I want to change the content/element of Quantity column dynamically. Normally, it should show the element with quantity displayed in it and when user click on element, I want to show the element so user can edit the quantity. I'm trying to implement as per "Example 2" on this knockout documentation link.
Following is my code :
Page Viewmodel
function OrderVM (vm) {
var self = this;
self.OrderNo= ko.observable(vm.OrderNo());
.....
.....
self.OrderedProducts = ko.observableArray([]);
for (i = 0; i < vm.OrderedProducts().length; i++) {
var p = new ProductVM(vm.OrderedProducts()[i]);
self.OrderedProducts.push(p);
}
.....
}
function ProductVM(vm) {
var self = this;
self.Code = ko.observable(vm.Code());
self.Name = ko.observable(vm.Name());
self.Quantity = ko.observable(vm.Quantity());
self.Price = ko.observable(vm.Price());
self.IsEditing = ko.observable(false);
this.edit = function () {
self.IsEditing(true);
}
}
In my Razor view I have following code :
<tbody data-bind="foreach:OrderedProducts">
<tr>
<td class="lalign"><span data-bind="text:Code"/></td>
<td class="lalign"><span data-bind="text:Name" /></td>
<td class="ralign" style="padding:1px!important;">
<span data-bind="visible: !IsEditing(), text: Quantity, click: edit"
style="width:100%;float:left;text-align:right;padding-right:10px;" />
<input data-bind="value: Quantity,visible:IsEditing,hasfocus:IsEditing"
style="width:100%;text-align:right;padding-right:10px;" />
</td>
<td class="ralign rightbordernone" style="padding-right:20px!important;"><span data-bind="text:Price"/></td>
</tr>
With above code, when I click on span element in my Quantity column of table, "edit" function is called and "IsEditing" value is set to true but I don't see input element visible in my cell. After clicking on span element, If I look at the html using "Inspect Element", I can still see the element only and not but on screen in my view, I see neither span nor input element.
This is very simple logic and executes as expected however final result on view is not as expected. Can anyone help me to detect what's wrong with above code?
The problem is tricky. It lies in the fact that span is not a self-closing element. This will work:
<td>
<span data-bind="visible: !IsEditing(), text: Quantity, click: edit"></span>
<input data-bind="value: Quantity, visible: IsEditing, hasfocus: IsEditing" />
</td>
Here's a full demo:
function ProductVM(vm) {
var self = this;
self.Code = ko.observable(vm.Code());
self.Name = ko.observable(vm.Name());
self.Quantity = ko.observable(vm.Quantity());
self.Price = ko.observable(vm.Price());
self.IsEditing = ko.observable(false);
this.edit = function () {
self.IsEditing(true);
}
}
ko.applyBindings({ OrderedProducts: [new ProductVM({
Code: function() { return 1; },
Name: function() { return "Apples"; },
Quantity: function() { return 10; },
Price: function() { return 12.50; }
})]})
span { padding: 5px; background: pink; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
(Click "10" e.g. the Quantity for demo.)
<table>
<tbody data-bind="foreach: OrderedProducts">
<tr>
<td><span data-bind="text:Code"></span></td>
<td><span data-bind="text:Name"></span></td>
<td>
<span data-bind="visible: !IsEditing(), text: Quantity, click: edit"></span>
<input data-bind="value: Quantity, visible: IsEditing, hasfocus: IsEditing" />
</td>
<td><span data-bind="text:Price"></span></td>
</tr>
</tbody>
</table>
Remember, the same holds for div elements, don't use them in a self-closing manner or Knockout will fool you when you least expect it.
Here is a sample for the problem, in this case someone selects toppings for a pizza (my real world problem is analogue to that):
http://jsfiddle.net/csabatoth/aUH2C/4/
HTML:
<h2>Pizza toppings (<span data-bind="text: toppings().length"></span>)</h2>
<table class="table table-bordered">
<thead><tr>
<th>Topping</th><th>Number of units</th>
</tr></thead>
<tbody data-bind="foreach: toppings">
<tr>
<td><select data-bind="options: $root.availableToppings(), value: name, optionsText: 'name'"></select></td>
<td><input data-bind="value: num" /></td>
<td>Remove</td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-primary" data-bind="click: addTopping, enable: toppings().length < 5">Add another topping</button>
JS:
// Class to represent a possible topping
function Topping(name) {
var self = this;
self.name = name;
// This will have other properties
}
// Class to represent a row in the grid
function ToppingRow(topping, num) {
var self = this;
self.topping = ko.observable(topping);
self.num = ko.observable(num);
self.toppingName = ko.computed(function() {
return self.topping().name;
});
}
function ToppingsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableToppings = ko.observableArray([
new Topping("Mushroom"),
new Topping("Pepperoni"),
new Topping("Cheese"),
new Topping("Olives"),
new Topping("Chicken")
]);
// Editable data
self.toppings = ko.observableArray([
new ToppingRow(self.availableToppings()[0], 1)
]);
// Operations
self.addTopping = function() {
self.toppings.push(new ToppingRow(self.availableToppings()[0], 1));
}
self.removeTopping = function(topp) { self.toppings.remove(topp) }
}
ko.applyBindings(new ToppingsViewModel());
What I would like is: when the user selects a topping, that option should disappear from the popup list. Once the user removes the topping, it should reappear in the popup. In other words: I don't want the user to add the same topping more than once. How to do that?
(Or now I think if I should approach this in a totally different way and would have a list with the toppings on the left, and the user could drag&drop to the right destination list from there...). In the real world example the number of "toppings" would be maybe some dozen I think.
You could simplify this slightly by having a topping selector with 1 drop down. Then when you click add it inserts the currently selected item to a selected toppings section and then removes the option from the available list.
If you are feeling clever you could also bind the drop-down to a computed collection of items that does not include already selected items. (underscore.js will also help with this immensely).
(Fiddle)
JS
// Class to represent a possible topping
function Topping(name) {
var self = this;
self.name = name;
// This will have other properties
}
// Class to represent a row in the grid
function ToppingRow(topping, num) {
var self = this;
self.topping = topping;
self.num = ko.observable(num);
self.toppingName = ko.computed(function() {
return self.topping.name;
});
}
function ToppingsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.allToppings = ko.observableArray([
new Topping("Mushroom"),
new Topping("Pepperoni"),
new Topping("Cheese"),
new Topping("Olives"),
new Topping("Chicken")
]);
self.selectedToppings = ko.observableArray([]);
self.availableToppings = ko.computed(function(){
return _.reject(self.allToppings(), function(topping) {
return _.contains(_.pluck(self.selectedToppings(), 'topping'), topping);
})
});
self.currentlySelectedTopping = ko.observable();
self.currentlySelectedToppingNumber = ko.observable(1);
// Operations
self.addTopping = function() {
self.selectedToppings.push(new ToppingRow(self.currentlySelectedTopping(), self.currentlySelectedToppingNumber()));
}
//self.removeTopping = function(topp) { self.toppings.remove(topp) }
}
ko.applyBindings(new ToppingsViewModel());
HTML
<h2>Pizza toppings</h2>
<table class="table table-bordered">
<thead><tr>
<th>Topping</th><th>Number of units</th>
</tr></thead>
<tbody>
<tr>
<td><select data-bind="options: availableToppings, value: currentlySelectedTopping, optionsText: 'name'"></select></td>
<td><input data-bind="value: currentlySelectedToppingNumber" /></td>
<td>Remove</td>
</tr>
<!-- ko foreach: selectedToppings -->
<tr><td data-bind="text: toppingName"></td><td data-bind="text: num"></td></tr>
<!-- /ko -->
</tbody>
</table>
<button type="button" class="btn btn-primary" data-bind="click: addTopping, enable: availableToppings().length">Add another topping</button>
I dont why you are making simple things difficult. Here is some modified version.
function Topping(name) {
var self = this;
self.name = name;
self.active = ko.observable(false)
self.toggle = function () {
self.active(!self.active())
}
// This will have other properties
}
// Class to represent a row in the grid
function ToppingRow(name, num) {
var self = this;
self.name = name;
self.num = num;
}
function ToppingsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableToppings = ko.observableArray([
new Topping("Mushroom"),
new Topping("Pepperoni"),
new Topping("Cheese"),
new Topping("Olives"),
new Topping("Chicken")
]);
self.list = ko.observableArray()
self.num = ko.observable(1)
self.selected = ko.observable()
// Operations
self.addTopping = function() {
self.list.push(new ToppingRow(self.selected(),self.num()));
self.setAvailableToppings(self.selected())
}
self.removeTopping = function(item) {
self.list.remove(item)
self.setAvailableToppings(item.name)
}
self.setAvailableToppings = function (name) {
var items = []
ko.utils.arrayForEach(self.availableToppings(),function (item) {
if(item.name == name){
item.toggle()
}
items.push(item)
})
self.availableToppings([])
self.availableToppings(items)
var selected = ko.utils.arrayFirst(self.availableToppings(),function (item) {
return item.active() == false
})
if(selected){
self.selected(selected.name)
}
}
self.setOptionDisable = function(option, item) {
ko.applyBindingsToNode(option, {disable: item.active()}, item);
}
}
$(document).ready(function(){
ko.applyBindings(new ToppingsViewModel());
})
And view
<h2>Pizza toppings (<span data-bind="text: list().length"></span>)</h2>
<table class="table table-bordered">
<thead><tr>
<th>Topping</th><th>Number of units</th>
</tr></thead>
<tbody data-bind="foreach: list">
<tr>
<td data-bind="text:name"></td>
<td data-bind="text: num"></td>
<td>Remove</td>
</tr>
</tbody>
</table>
<br clear="all"/>
<select data-bind="
options: $root.availableToppings(),
value: $root.selected,
optionsText: 'name',
optionsValue : 'name',
optionsAfterRender: $root.setOptionDisable,
enable: list().length < 5
">
</select>
<input data-bind="value: $root.num,enable: list().length < 5" />
<br clear="all"/>
<button type="button" class="btn btn-primary"
data-bind="
click: addTopping,
enable: list().length < 5
">Add another topping</button>
Fiddle Demo
The problem is that the data-binding doesn't work.
I have an observableArray() containing claims. Each claim has an observableArray() of expenses, which is one item from the self.pc_listOfExpenses().
Here's the structure of both arrays:
self.pc_listOfClaims = ([
ID: 34
claimAgainst: "CompanyName"
date: "2010-10-10"
desc: "Description"
**expenses: Object[0]** // <= This one should be an array.
]);
self.pc_listOfExpenses = ko.observableArray([
ID: "34"
**Array** // <= This is the array of "Expense" Objects
]);
Note: *Do not bother about the correct syntax above. I fill in the arrays from the services, using JSON. The Object[0] is what I see in the console. *
The idea is to map each claim, with the corresponding array of expenses:
If we have claimID = 34, then in the self.pc_listOfExpenses() array we have 34=>Array().
Here's the Knockout code:
//#region Preview Claims Block
/**************************************************/
/* Preview Claims Block */
/**************************************************/
self.pc_listOfClaims = ko.observableArray([]);
self.pc_showDetailsArr = ko.observableArray([]);
self.pc_listOfExpenses = ko.observableArray([]);
// Get userID-specified Claims using WS
pc_GetSpecifiedClaims(self);
for (var i = 0; i < self.pc_listOfClaims().length; i++) {
self.pc_showDetailsArr()[self.pc_listOfClaims()[i].ID] = ko.observable(false);
}
self.pc_showMoreDetails = function (claim) {
if (typeof claim !== "undefined") {
self.pc_showDetailsArr()[claim.ID](!self.pc_showDetailsArr()[claim.ID]());
pc_GetClaimExpenses(claim.ID);
for (var i = 0; i < self.pc_listOfExpenses()[claim.ID].length; i++) {
self.pc_listOfClaims()[claim_id]["expenses"]().push(self.pc_listOfExpenses()[claim.ID][i]);
}
}
}
//#endregion
Here is the Web Service:
function pc_GetClaimExpenses(claimID) {
$.ajax({
cache: false,
async: false,
type: 'GET',
url: '/DesktopModules/UltimateExpenses/API/Claims/GetSpecifiedExpensesAsJSONString',
success: function (data) {
self.pc_listOfExpenses()[claimID] = JSON.parse(data);
//console.log(JSON.parse(data));
}
});
}
Here's the view:
<table id="claimsDataTable">
<tbody data-bind="foreach: pc_listOfClaims">
<tr>
<td data-bind="text: claimAgainst"></td>
<td data-bind="text: projectName"></td>
<td data-bind="text: taskName"></td>
<td data-bind="text: price"></td>
<td data-bind="text: status"></td>
<td data-bind="text: date"></td>
<td class="actionOptions">
M
</td>
</tr>
<tr>
<td colspan="7" data-bind="visible: pc_showDetailsArr()[$data.ID]">
<!-- This is the part which does not work-->
<div data-bind="foreach: expenses">
<span data-bind="text: ID"></span>
<span data-bind="text: Type"></span>
<span data-bind="text: Price"></span>
</div>
</td>
</tr>
</tbody>
</table>
To solve the problem, I created a Claim class, with an observableArray() for the expenses. Then using a loop I created each Claim and pushed every expense into the expenses observableArray(). Here's the code I hade to add/change. I hope it helps someone else too.
The Claim class:
function Claim(ID, claimAgainst, userID, projectName, taskName, desc, price, status, date) {
this.ID = ID;
this.claimAgainst = claimAgainst;
this.userID = userID;
this.projectName = projectName;
this.taskName = taskName;
this.desc = desc;
this.price = ko.observable(price);
this.status = ko.observable(status);
this.date = date;
this.expenses = ko.observableArray([]);
}//Claim
The Web service to get the claims and create the objects:
function pc_GetSpecifiedClaims(self) {
$.ajax({
cache: false,
async: false,
type: 'GET',
url: '/DesktopModules/UltimateExpenses/API/Claims/GetSpecifiedClaimsAsJSONString',
success: function (data) {
tempArr = JSON.parse(data);
for (var i = 0; i < tempArr.length; i++) {
self.pc_listOfClaims.push(new Claim(tempArr[i].ID, tempArr[i].claimAgainst, tempArr[i].userID,
tempArr[i].projectName, tempArr[i].taskName, tempArr[i].desc, tempArr[i].price,
tempArr[i].status, tempArr[i].date));
}
}
});
}
And finally I pushed the array from the self.pc_listOfExpenses(), using the corresponding claimID, into the self.pc_listOfClaims().expenses():
for (var i = 0; i < self.pc_listOfExpenses()[claim.ID].length; i++) {
self.pc_listOfClaims()[claim_id].expenses.push(self.pc_listOfExpenses()[claim.ID][i]);
}
This can't work :
self.pc_listOfExpenses()[claimID] = JSON.parse(data);
Because you are modifying the internal array of the observableArray().
I am not sure, but you could try this :
var items = self.pc_listOfExpenses();
items[claimID] = JSON.parse(data);
self.pc_listOfExpenses(items);
I hope it helps.