View data binding in nested dynamic observableArray - javascript

I need to put observableArray with dynamic size inside observableArray and bind data to View.
View is render values from newData, but not update it in newData, when i edit it in View.
ko.applyBindings(new (function () {
var self = this;
self.lengthNewData = ko.observable(2);
self.newData = ko.observableArray();
self.AddDataStrings = function () {
let newString = ko.observableArray();
for(let i0 = 0; i0 < self.lengthNewData(); i0++)
newString.push(i0);
self.newData.push(newString);
}
self.SendData = function () {
alert(ko.toJSON(self.newData));
}
})());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<span data-bind="visible: !newData().length">Number of rows: <input data-bind="value: lengthNewData"/></span>
<input type="button" value="Add" data-bind="click: $root.AddDataStrings"/>
<input type="button" value="Send" data-bind="visible: newData().length, click: $root.SendData"/><br>
<table>
<tbody data-bind="foreach: newData">
<tr data-bind="foreach: $data">
<td><input data-bind="value: $data"/></td>
</tr>
</tbody>
</table>
https://jsfiddle.net/tvxyyzkp/6/
Push Add, edit it and push Send. Data was not modified!
Why and What need to change?

There are two immediate mistakes in your code.
You do not push observables into your newString. You should do:
newString.push(ko.observable(i0));
You bind your inputs to $data. $data contains the unwrapped data value, i.e. it's not observable. Bind to $rawData in such a setup.
This works:
ko.applyBindings(new(function() {
var self = this;
self.lengthNewData = ko.observable(2);
self.newData = ko.observableArray();
self.AddDataStrings = function() {
let newString = ko.observableArray();
for (let i0 = 0; i0 < self.lengthNewData(); i0++)
newString.push(ko.observable(i0));
self.newData.push(newString);
}
self.SendData = function() {
alert(ko.toJSON(self.newData));
}
})());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<span data-bind="visible: !newData().length">Number of rows: <input data-bind="value: lengthNewData"/></span>
<input type="button" value="Add" data-bind="click: AddDataStrings" />
<input type="button" value="Send" data-bind="visible: newData().length, click: SendData" /><br>
<table>
<tbody data-bind="foreach: newData">
<tr data-bind="foreach: $data">
<td><input data-bind="value: $rawData" /></td>
</tr>
</tbody>
</table>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

Related

Knockout JS: Creating dynamic table columns

Using Knockout JS:
I have a requirement as.
I have a table with 2 static columns where each has a text-box. I also have a add row button outside the table and one remove row button along each row.
When the user clicks add row it adds a row to the table and I can see two columns with textbox in each. User can add more rows if required by clicking add row and click remove row to remove rows.
This all has been setup and works fine as :
https://jsfiddle.net/aman1981/xmd1xobm/14/
My issue is there is also an Get Columns button. When the user clicks this button I fetch a list of columns and want to add these columns with headers b/w the already existing columns of the table.Each of these columns also need to have a textbox as well.
For ex I would the list of columns as:
var columnsList = 'name, address, zip';
I am not sure how to add columns dynamically. Would appreciate inputs.
Here is the setup of my table:
<table class="table table-bordered">
<thead class="mbhead">
<tr class="mbrow">
<th>SIID</th>
<th>Comment</th>
</tr>
</thead>
<tbody data-bind="foreach: data">
<tr>
<td>
<input type="text" data-bind="text: SIID" class="form-control textbox" />
</td>
<td>
<input type="text" data-bind="text: Comment" class="form-control textbox" />
</td>
<td>
<input type="button" value="Remove Row" data-bind="click: $parent.removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>
<div class="col-xs-12 col-sm-6">
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
<input type="button" value="Get Columns" class="btn btn-primary" data-bind="click: addColumns" />
</div>
Anyone?
Nice for you i have a dynamic table component from my previous project:
var observable = ko.observable;
var pureComputed = ko.pureComputed;
var observableArray = ko.observableArray;
var unwrap = ko.unwrap;
var data = observableArray([{
a: 123,
b: 234,
c: 345
},{
a: 1231,
b: 2341,
c: 3451
},{
a: 1232,
b: 2342,
c: 3425
},{
a: 1233,
b: 2343,
c: 3453
}]);
var columns = observableArray([{
field: "a",
displayName: "A"
},{
field: "b",
displayName: "B (i can even change the title)"
}])
function viewModel(params) {
var paramColumns = params.columns;
var paramData = params.data;
var paramFieldKey = params.fieldKey || "field";
var paramDisplayNameKey = params.displayNameKey || "displayName";
var koColumnHeaders = pureComputed(function () {
var columns = paramColumns();
var columnHeaders = [];
var fieldKey = unwrap(paramFieldKey);
var displayNameKey = unwrap(paramDisplayNameKey);
for (var i in columns) {
var column = columns[i];
columnHeaders.push({
field: column[fieldKey],
displayName: column[displayNameKey]
})
}
return columnHeaders;
})
var koRows = pureComputed(function () {
var data = paramData();
var columns = paramColumns();
var fieldKey = unwrap(paramFieldKey);
var rows = [];
for (var i in data) {
var datum = data[i];
var cells = []
var row = {
entity: data,
cells: cells
};
for (var j in columns) {
var column = columns[j];
cells.push(datum[column[fieldKey]] || "");
}
rows.push(row);
}
return rows;
});
return {
rows: koRows,
columns: koColumnHeaders,
}
}
ko.applyBindings(new viewModel({
data: data,
columns: columns
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table table-bordered" border="1">
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: displayName">
</th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr>
<!-- ko foreach: cells -->
<td class="" data-bind="text: $data"></td>
<!-- /ko -->
</tr>
</tbody>
</table>
I was able to resolve this using the post at:
Knockout JS: Get Textbox data from Table under for-each binding
Here is my code:
(function() {
var ViewModel = function() {
var self = this;
self.valuesData = ko.observableArray();
self.columns = ko.computed(function() {
if (self.valuesData().length === 0)
return [];
return ValuesData.columns;
});
self.addRow = function() {
self.valuesData.push(new ValuesData());
};
self.Save = function() {
alert('Data:')
};
self.removeRow = function(data) {
self.valuesData.remove(data);
};
}
// Dynamic values.
var ValuesData = function(siid, comment) {
var self = this;
// Add observables dynamically for all relevant columns.
for (var i = 0; i < ValuesData.columns.length; i++) {
var column = ValuesData.columns[i];
self[column.Property] = ko.observable(column.InitialValue)
}
};
// Basic column definition.
ValuesData.columns = [{
Caption: 'SIID',
Property: 'SIID',
InitialValue: undefined
},
{
Caption: 'Column 1',
Property: 'Col1',
InitialValue: undefined
},
{
Caption: 'Column 2',
Property: 'Col2',
InitialValue: 'banana'
},
{
Caption: 'Comment',
Property: 'Comment',
InitialValue: undefined
}
]
vm = new ViewModel()
ko.applyBindings(vm);
// add initial row.
vm.addRow();
})();
Here is the html part:
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-
min.js"></script>
<br><br>
<table>
<thead>
<!-- NEW: use ko foreach with 'as' to have an alias for accessing $data. -->
<tr data-bind="foreach: { data: columns, as: 'column'}">
<th> <span data-bind="text: column.Caption"></span>
</th>
</tr>
</thead>
<tbody data-bind="foreach: { data: valuesData, as: 'rowData'}">
<tr data-bind="foreach: { data: $parent.columns, as: 'column' }">
<!-- NEW: bind to the corresponding property/observable in ValuesData -->
<td><input type="text" class="form-control textbox" data-bind="textInput:
rowData[column.Property]" /> </td>
</tr>
<tr>
<td>
<input type="button" value="Remove Row" data-bind="click:
$parent.removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>

Computed property based of external array Knockout JS

I just starting out with Knockout and running through a pluralsite course.
I have a (presumably basic) question about a computed property based on the parent array:
Given the below code how do I make it work so that the Amount property for each item in my.vm.attendees is always the totalCost divided by number of attendees. E.g. with 4 attendees in the collection amount for each should be 25.
This should be automatically updated as you add and remove items.
<script type="text/javascript">
$(function () {
var total = 100;
//Attendee construction
my.Attendee = function () {
this.Name = ko.observable();
this.Amount = ko.computed(function () {
return total / this.numberOfAttendees;
}, my.vm);
};
my.vm = {
//observable array of attendees
attendees: ko.observableArray([new my.Attendee()]),
addAttendee: function () {
my.vm.attendees.push(new my.Attendee());
},
numberOfAttendees: function () {
my.vm.attendees.lenght + 1; //zero based
}
}
ko.applyBindings(my.vm);
});
</script>
I would probably do something like this.
function attendee(name, amount) {
var self = this;
this.name = ko.observable(name);
this.amount = ko.observable(amount);
}
function model() {
var self = this;
this.attendees = ko.observableArray();
this.total = ko.computed(function() {
var total = 0;
ko.utils.arrayForEach(this.attendees(), function(item) {
var value = parseFloat(item.amount());
if (!isNaN(value)) {
total += value;
}
});
return total.toFixed(2);
}, this);
this.average = ko.pureComputed(function() {
return self.total() / self.attendees().length;
}, this);
this.remove = function(row) {
self.attendees.remove(row);
}
this.name = ko.observable('');
this.amount = ko.observable('');
this.add = function() {
self.attendees.push(new attendee(self.name(), self.amount()));
self.amount('');
self.name('');
}
}
var mymodel = new model();
$(document).ready(function() {
ko.applyBindings(mymodel);
mymodel.attendees.push(new attendee('Bob', 25));
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Amount</th>
<td>Delete</td>
</tr>
</thead>
<tbody data-bind="foreach: attendees">
<tr>
<td data-bind="text:name"></td>
<td data-bind="text:amount"></td>
<td>
<button class="btn btn-danger" data-bind="click: $parent.remove">
X
</button>
</td>
</tr>
</tbody>
<tfooter>
<tr>
<td colspan=2>Average:
<span data-bind="text:average">
</span>
</td>
</tr>
</tfooter>
</table>
<form class="form form-inline">
<label class="sr-only" for="inlineFormInput">Name</label>
<input type="text" class="form-control" id="inlineFormInput" placeholder="enter name" data-bind="textInput: name">
<label class="sr-only" for="inlineFormInputGroup">Amount</label>
<div class="input-group ">
<div class="input-group-addon">$</div>
<input type="text" class="form-control" id="inlineFormInputGroup" placeholder="amount" data-bind="textInput: amount">
</div>
<button type="buttont" class="btn btn-primary" data-bind="click: add">add row </button>
</form>
The "Amount" computed will be recalculated whenever any child observables are updated. Therefore you'll need to make "total" an observable if you want it to trigger a change, and you'll need to make "numberOfAttendees" a computed itself so that it can update when my.vm.attendees gets updated, and that can then cascade to an update of the "Amount" computed.

Add and Remove List Knockout

Im trying to make a calculator that can add and subtract values. At the same time, I wanted user to be able to add and remove list. My add and remove list button doesn't work. Can someone help me?
here are my javascript code:
var ViewModel = function() {
var self = this;
self.value1 = ko.observable(0),
self.value2 = ko.observable(0),
self.mathOperator = ko.observableArray(['+', '-']);
self.selectedOperator = ko.observableArray(['+']);
self.calculateValues = ko.computed(function(){
var selectedOperator = self.selectedOperator()[0],
value1 = self.value1(),
value2 = self.value2();
switch(selectedOperator[0]){
case '+':
return parseInt(value1) + parseInt(value2);
case '-':
return parseInt(value1) - parseInt(value2);
}
});
self.addValue = funtion() {
self.selectedOperator.push(self.selectedOperator()[0]);
}
self.removeValue = function(val) {
self.selectedOperator.remove(val)
}
}
ko.applyBindings(new ViewModel());
and here are my html code:
<div id="MyCalc">
<table>
<tbody data-bind="foreach: selectedOperator">
<tr>
<td>
<label>Value1</label>
<input type="text" data-bind="value: value1" />
</td>
<td>
<select data-bind="options: mathOperator, selectedOptions: selectedOperator,"></select>
</td>
<td>
<button data-bind="click: removeValue">Remove</button>
</td>
</tr>
<tr>
<td>
<label>Value2</label>
<input type="text" data-bind="value: value2" />
</td>
<td>
<select data-bind="options: mathOperator, selectedOptions: selectedOperator,"></select>
</td>
<td>
<button data-bind="click: removeValue">Remove</button>
</td>
</tr>
<button data-bind="click:addvalue">Add Another Value</button>
</tbody>
</table>
<div id="result">Total:<span data-bind="text: calculateValues" />
</div>
or for easy viewing, this is the jdfiddle link. http://jsfiddle.net/sqkr65td/

knockout js grid swap input fields if data exists

I have an editable grid in which I populate with data after a user logs in with ajax.
I'm populating it with a device list and shipping information. Inside the device list json I have a Boolean "byod", if the selected row has the device with this data set to "0" I'd like to swap the "MAC Address" text field with the "Ship To" drop down.
fiddle is here http://jsfiddle.net/QTUqD/15/, code is below:
<form id="extMngForm">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Extension</th>
<th>Name</th>
<th>Email</th>
<th>Pin</th>
<th>Device</th>
<th>MAC Address</th>
<th>Ship To</th>
<th style="width: 100px; text-align:right;"></th>
</tr>
</thead>
<tbody data-bind=" template:{name:templateToUse, foreach: pagedList }"></tbody>
</table>
<p class="pull-right addExt"><a class="btn btn-primary" data-bind="click: $root.add" href="#" title="edit"><i class="icon-plus"></i> Add Extension</a></p>
<div class="pagination pull-left" data-bind='visible: pagedList().length > 0'>
<ul><li data-bind="css: { disabled: pageIndex() === 0 }">Previous</li></ul>
<ul data-bind="foreach: allPages">
<li data-bind="css: { active: $data.pageNumber === ($root.pageIndex() + 1) }"></li>
</ul>
<ul><li data-bind="css: { disabled: pageIndex() === maxPageIndex() }">Next</li></ul>
</div>
<br clear="all" />
<script id="extItems" type="text/html">
<tr>
<td style="width:20px;" data-bind="text: extension"></td>
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
<td style="width:20px;" data-bind="text: vmpin"></td>
<td data-bind="text: device.asObject && device.asObject() && device.asObject().name"></td>
<td data-bind="text: macAddress"></td>
<td data-bind="text: shipTo"></td>
<td class="buttons">
<a class="btn" data-bind="click: $root.edit" href="#" title="edit"><i class="icon-edit"></i></a>
<a class="btn" data-bind="click: $root.remove" href="#" title="remove"><i class="icon-remove"></i></a>
</td>
</tr>
</script>
<script id="editExts" type="text/html">
<tr>
<td style="width:20px;"><input style="width:65px;min-width: 65px;" data-errorposition="b" class="required" name="extension" data-bind="value: extension" /></td>
<td><input data-errorposition="b" class="required" name="name" data-bind="value: name" /></td>
<td><input data-errorposition="b" class="required" name="email" data-bind="value: email" /></td>
<td style="width:20px;"><input style="width:65px;min-width: 65px;" data-errorposition="b" class="required" name="vmpin" data-bind="value: vmpin" /></td>
<td>
<select data-bind="options: $root.devicesForItem($data), optionsText: 'name', optionsValue: 'id', value: device, valueAsObject: 'asObject'"></select>
</td>
<td><input name="macAddress" data-bind="value: macAddress" /></td>
<td><select style="width:100px;" data-bind="options: $root.addressList, optionsText: 'locationName', optionsValue: 'locationName', value: shipTo"></select></td>
<td class="buttons">
<a class="btn btn-success" data-bind="click: $root.save" href="#" title="save"><i class="icon-ok"></i></a>
<a class="btn" data-bind="click: $root.remove" href="#" title="remove"><i class="icon-remove"></i></a>
</td>
</tr>
</script>
</form>
window.ExtListViewModel = new function () {
var self = this;
window.viewModel = self;
self.list = ko.observableArray();
self.pageSize = ko.observable(10);
self.pageIndex = ko.observable(0);
self.selectedItem = ko.observable();
self.extQty = ko.observable(20);
self.devices = ko.observableArray([{"id":"gxp2100","name":"Grandstream GXP-2100","qty":"2","byod":"1"}, {"id":"gxp2100","name":"Grandstream GXP-2100 (BYOD)","qty":"1","byod":"0"}, {"id":"pcom331","name":"Polycom 331","qty":"2","byod":"0"}, {"id":"pcom331","name":"Polycom 331 (BYOD)","qty":"1","byod":"1"}]);
self.addressList = ko.observableArray(['addressList']);
self.availableDevices = ko.computed(function() {
var usedQuantities = {};
self.list().forEach(function(item) {
var device = item.device();
if (device) {
usedQuantities[device.id] = 1 + (usedQuantities[device.id] || 0);
}
});
return self.devices().filter(function(device) {
var usedQuantity = usedQuantities[device.id] || 0;
return device.qty > usedQuantity;
});
});
self.devicesForItem = function(item) {
var availableDevices = self.availableDevices();
return self.devices().filter(function(device) {
return device === item.device() || availableDevices.indexOf(device) !== -1;
});
}
self.edit = function (item) {
self.selectedItem(item);
};
self.cancel = function () {
self.selectedItem(null);
};
self.add = function () {
var newItem = new Extension();
self.list.push(newItem);
self.selectedItem(newItem);
self.moveToPage(self.maxPageIndex());
};
self.remove = function (item) {
if (confirm('Are you sure you wish to delete this item?')) {
self.list.remove(item);
if (self.pageIndex() > self.maxPageIndex()) {
self.moveToPage(self.maxPageIndex());
}
}
};
self.save = function () {
self.selectedItem(null);
};
self.templateToUse = function (item) {
return self.selectedItem() === item ? 'editExts' : 'extItems';
};
self.pagedList = ko.dependentObservable(function () {
var size = self.pageSize();
var start = self.pageIndex() * size;
return self.list.slice(start, start + size);
});
self.maxPageIndex = ko.dependentObservable(function () {
return Math.ceil(self.list().length / self.pageSize()) - 1;
});
self.previousPage = function () {
if (self.pageIndex() > 0) {
self.pageIndex(self.pageIndex() - 1);
}
};
self.nextPage = function () {
if (self.pageIndex() < self.maxPageIndex()) {
self.pageIndex(self.pageIndex() + 1);
}
};
self.allPages = ko.dependentObservable(function () {
var pages = [];
for (i = 0; i <= self.maxPageIndex() ; i++) {
pages.push({ pageNumber: (i + 1) });
}
return pages;
});
self.moveToPage = function (index) {
self.pageIndex(index);
};
};
ko.applyBindings(ExtListViewModel, document.getElementById('extMngForm'));
function Extension(extension, name, email, vmpin, device, macAddress, shipTo){
this.extension = ko.observable(extension);
this.name = ko.observable(name);
this.email = ko.observable(email);
this.vmpin = ko.observable(vmpin);
this.device = ko.observable(device);
this.macAddress = ko.observable(macAddress);
this.shipTo = ko.observable(shipTo);
};
ExtListViewModel.addressList = [{"shipping_address_street":"555 Lane","shipping_address_state":"TX","shipping_address_city":"Dallas","shipping_address_postalcode":"75000","locationName":"Preset"}, {"shipping_address_street":"555 Lane","shipping_address_state":"TX","shipping_address_city":"Dallas","shipping_address_postalcode":"75000","locationName":"Home"}];
//Shows device name not value (knockout extension)
ko.bindingHandlers.valueAsObject = {
init: function(element, valueAccessor, allBindingsAccessor) {
var value = allBindingsAccessor().value,
prop = valueAccessor() || 'asObject';
//add an "asObject" sub-observable to the observable bound against "value"
if (ko.isObservable(value) && !value[prop]) {
value[prop] = ko.observable();
}
},
//whenever the value or options are updated, populated the "asObject" observable
update: function(element, valueAccessor, allBindingsAccessor) {
var prop = valueAccessor(),
all = allBindingsAccessor(),
options = ko.utils.unwrapObservable(all.options),
value = all.value,
key = ko.utils.unwrapObservable(value),
keyProp = all.optionsValue,
//loop through the options, find a match based on the current "value"
match = ko.utils.arrayFirst(options, function(option) {
return option[keyProp] === key;
});
//set the "asObject" observable to our match
value[prop](match);
}
};
First of all, like I showed you in your other recent post, don't use optionsValue binding for your selects if you want the value to be the object itself (and then you don't need that valueAsObject stuff). So:
<select data-bind="options: $root.devicesForItem($data), optionsText: 'name', value: device"></select>
Second, your IDs need to be unique (not like in your current example) because your code depends on that.
Then, the rest is easy, you just need a simple computed boolean in your Extension objects that says whether the MAC address or the shipping thing is shown, e.g.:
this.showMac = ko.computed(function() {
if (self.device())
return self.device().byod !== '0';
return true;
});
And use this computed in the bindings, e.g. <!-- ko if: showMac --> or <td data-bind="text: showMac() ? macAddress : shipTo>"
Fiddle: http://jsfiddle.net/antishok/QTUqD/16/

knockoutjs observablearray make individual item observable

i was looking # 2'nd tutorial "Working with lists and colection" on Knockoutjs.com: http://learn.knockoutjs.com/#/?tutorial=collections
Here's HTML:
Your seat reservations ()
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
</tr></thead>
<!-- Todo: Generate table body -->
<tbody data-bind="foreach: seats">
<tr>
<td> <input data-bind="value: name()"/></td>
<td> <select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
<td data-bind="text: formatterPrice"></td>
<!--<td> Remove</td>-->
<td> <button data-bind="click: $root.removeSeat">Remove</button></td>
</tr>
</tbody>
</table>
<button data-bind="click: addSeat, enable: seats().length < 5">Reserve another seat</button>
<h3 data-bind="visible: totalSurcharge() > 0">
Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>
<span data-bind="text: seats()[0].name()" ></span> <br/>
<span data-bind="text: seats()[0].meal().mealName" />
Here's ViewModel:
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = ko.observable(name);
self.meal = ko.observable(initialMeal);
self.formatterPrice = ko.computed(function() {
var price = self.meal().price;
return price ? "$" + price.toFixed(2) : "None";
});
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableMeals = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.958989 },
{ mealName: "Ultimate (whole zebra)", price: 290.00000 }
];
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[1])
]);
self.addSeat = function() {
self.seats.push(new SeatReservation("Steve", self.availableMeals[2]))
};
self.removeSeat = function(seat) {
self.seats.remove(seat);
}
self.totalSurcharge = ko.computed(function() {
var total = 0;
for(var i = 0; i < self.seats().length; i++) {
total += self.seats()[i].meal().price;
}
// alert(total);
return total;
});
}
ko.applyBindings(new ReservationsViewModel());
When i try to change "name" in textbox, my observableArray (seats) doesn't seem to change. Still my span # bottom shows "Steve" if i try to change first row's textbox.
I've made name() as observable same as meal, and if i change meal (dropdown), my observableArray (seats) seems working.
Please help!
at
<td> <input data-bind="value: name()"/></td>
use <td> <input data-bind="value: name"/></td>
and at <span data-bind="text: seats()[0].name()" ></span> <br/> you want <span data-bind="text: seats()[0].name" ></span> <br/>

Categories