Knockout.js options binding not working inside ViewModel - javascript

I'm trying to bind values from observabeArray to select element. This observable array is the part of view model that binding to table with foreach. Unfortunately it's not working - I got just two empty elements.
JavaScript/jQuery:
<script>
// heres what we are going to use for binding parameters
var Roles = function (name, id) {
this.Role = name;
this.id = id;
};
var Sexes = function (name, id) {
this.Sex = name;
this.id = id;
}
function UsersViewModel() {
//This is array values that I want to bind to select
rolex: ko.observableArray([
new Roles("Admin", 3),
new Roles("User", 1),
new Roles("Operator", 2)
]);
sexx: ko.observableArray([
new Sexes("Муж", 1),
new Sexes("Жен", 0)
]);
var self = this;
//self.Id = ko.observable();
//self.Login = ko.observable("");
//self.Password = ko.observable("");
//self.Role = ko.observable();
//self.Sex = ko.observable();
//var user = {
// Id: self.Id,
// Login: self.Login,
// Password: self.Password,
// Role: self.Role,
// Sex: self.Sex
//};
self.user = ko.observable();
self.users = ko.observableArray();
var baseUri = '/api/users';
$("#adduser").click(function () {
var json = '{"Login":"' + $("#login").val() + '", "Password":"' + $("#password").val() + '", Sex":' + $("#_sex option:selected").val() + ', "Role":' + $("#_role option:selected").val() + '}';
$.ajax({
url: baseUri,
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: json,
success: function (data) {
$("#notification").text("Пользователь успешно добавлен!");
$('#notification').removeClass("hidden");
self.users.push(data);
setTimeout(function () {
$('#notification').addClass("hidden");
}, 3000);
}
});
});
self.remove = function (user) {
$.ajax({ type: "DELETE", url: baseUri + '/' + user.Id })
.done(function () {
$("#notification").text("Пользователь успешно удален!");
$('#notification').removeClass("hidden");
self.users.remove(user);
setTimeout(function () {
$('#notification').addClass("hidden");
}, 3000);
});
}
self.update = function (user) {
$.ajax({ type: "PUT", url: baseUri + '/' + user.Id, data: user })
.done(function () {
$("#notification").text("Изменения сохранены!");
$('#notification').removeClass("hidden");
setTimeout(function () {
$('#notification').addClass("hidden");
}, 3000);
});
}
$.getJSON(baseUri, self.users);
}
$(document).ready(function () {
ko.applyBindings(new UsersViewModel());
})
</script>
And here is table that show all data including mentioned selects.
HTML:
<table class="pure-table">
<thead>
<tr>
<td></td>
<td>#</td>
<td>Логин</td>
<td>Пароль</td>
<td>Роль</td>
<td>Пол</td>
</tr>
</thead>
<tbody data-bind="foreach: users">
<tr>
<td>
<input type="button" value="Сохранить" data-bind="click: $root.update" class="pure-button" />
<input type="button" value="Удалить" data-bind="click: $root.remove" class="pure-button" />
</td>
<td data-bind="text: $data.ID"></td>
<td>
<input type="text" data-bind="value: $data.Login" />
</td>
<td>
<input type="text" data-bind="value: $data.Password" />
</td>
<td>
<select data-bind="options: rolex, optionsText: 'Role'">
</select>
</td>
<td>
<select id="sex" data-bind="options: sexx, optionsText: 'Sex'">
</select>
</td>
</tr>
</tbody>
</table>

There are several changes that need to be made. First, your html needs to use the $root:
<td>
<select data-bind="options: $root.rolex, optionsText: 'Role'"></select>
</td>
<td>
<select id="sex" data-bind="options: $root.sexx, optionsText: 'Sex'"></select>
</td>
The code below works (see comments with what was changed):
var Roles = function (name, id) {
this.Role = name;
this.id = id;
};
var Sexes = function (name, id) {
this.Sex = name;
this.id = id;
};
function UsersViewModel() {
//You should assign self on the first line and use it to assign all properties
var self = this;
self.rolex = ko.observableArray([
new Roles("Admin", 3),
new Roles("User", 1),
new Roles("Operator", 2)]);
self.sexx = ko.observableArray([
new Sexes("Муж", 1),
new Sexes("Жен", 0)]);
self.user = ko.observable();
self.users = ko.observableArray();
//You should not add call to $("#adduser").click(...) here, it seems it belongs outside of model
self.remove = function (user) {
//Did not test, but it probably works
};
self.update = function (user) {
//Did not test, but it probably works
};
return self;
}
// You can use such code to bind the values:
$(function(){
//Create the model
var model = new UsersViewModel();
//Apply bindings
ko.applyBindings(model);
//Push the value to the array
model.users.push({
Id: 1,
Login: "Login",
Password: "Psw",
Role: 3,
Sex: 1
});
});

Related

Cascaded Drop Down List with search box

I'm trying to use cascaded Drop Down for a project, but with a bit of a twist. For Power Users, they can enter a stock code and search. The retrieved information then updates the Parent Drop Down and the cascaded Drop Down selection.
Using a click event, I can search the entered value and it returns all the needed information. I can update the Parent to Display the correct information, But unable to get the child to display. It's stuck on showing " -- Select --" Populating the drop down's with data to select from works great. Could really use some insight and help.. Got myself stumped on the child. Thanks..
I followed this example to setup the Dropdowns. asp.net MVC cascading dropdown lists
<Controller>
public ActionResult Create()
{
ViewData["User"] = User.Identity.GetUserName();
BindPartType();
return View();
}
public void BindPartType()
{
partsmanagementEntities5 parttypelist = new partsmanagementEntities5(); //Parts
var parttype = parttypelist.parttypes.ToList();
List<SelectListItem> pli = new List<SelectListItem>();
pli.Add(new SelectListItem { Text = "--Select Catagory--", Value = "0" });
foreach (var m in parttype)
{
pli.Add(new SelectListItem { Text = m.PartType1, Value = m.idPartType.ToString() });
ViewBag.PartType = pli;
}
}
public JsonResult GetInventory(int? id)
{
partsmanagementEntities5 partlist = new partsmanagementEntities5();
var ddlpart = partlist.parts.Where(x => x.PartType == id).ToList();
List<SelectListItem> lipart = new List<SelectListItem>();
lipart.Add(new SelectListItem { Text = "--Select Inventory--", Value = "0" });
if (ddlpart != null)
{
foreach (var x in ddlpart)
{
lipart.Add(new SelectListItem { Text = x.PartDescription, Value = x.idParts.ToString() });
}
}
return Json(new SelectList(lipart, "Value", "Text", JsonRequestBehavior.AllowGet));
}
public JsonResult Check(string id)
{
partsmanagementEntities5 partlist = new partsmanagementEntities5();
StringBuilder test = new StringBuilder();
if(id != null && id != "")
{
foreach (char c in id)
{
if (!char.IsNumber(c))
test.Append(c);
}
var ddlpartnumber = partlist.parts.Where(x => x.PartNumber == id.ToString());
PartDetails li = new PartDetails();
foreach (var item in ddlpartnumber.ToList())
{
li.PartNumber = item.PartNumber;
li.PartPrice = item.PartPrice;
li.idParts = item.idParts;
li.EHF = item.EHF;
li.PartDescription = item.PartDescription;
li.PartImage = item.PartImage;
li.partImageContentType = item.partImageContentType;
li.unit = item.unit;
li.PartType = item.PartType;
li.VendorPartNumber = item.VendorPartNumber;
}
return Json(li, JsonRequestBehavior.AllowGet);
}
return Json("", JsonRequestBehavior.AllowGet);
}
<View>
<table>
<tr>
<td style="padding-left:0.8ex;padding-top:0.8ex">#Html.Label("Catagory: ")</td>
<td>
#Html.DropDownListFor(model => model.PartType, ViewBag.PartType as List<SelectListItem>, new { style = "width: 800px;" })
#Html.ValidationMessageFor(model => model.PartType, "", new { #class = "text-danger" })
</td>
<td style="padding-left:6ex;padding-top:0.8ex"></td>
</tr>
<tr>
<td style="width:1px;white-space:nowrap;padding-left:0.8ex">#Html.Label("Inventory: ")</td>
<td>
#Html.DropDownListFor(model => model.PartNumber, new SelectList(string.Empty, "Value", "Text"), "--Select Inventory--", new { style = "width:900px" })
#Html.ValidationMessageFor(model => model.PartNumber, "", new { #class = "text-danger" })
</td>
</tr>
<tr>
<td style="width:1px;white-space:nowrap;padding-left:6ex">#Html.Label("Or choose:")</td>
</tr>
<tr>
<td style="width:1px;white-space:nowrap;padding-left:0.8ex">#Html.Label("Enter Valid Part #: ")</td>
<td><input type="text" name="CheckPartNumber" id="CheckPartNumber"> <input type="button" id="Search" value="Search" class="btn btn-default" />
</tr>
</table>
<script src="~/Scripts/jquery-3.0.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#PartType").change(function () {
$("#PartNumber").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("GetInventory", "partrequests")',
dataType: 'json',
data: { id: $("#PartType").val() },
success: function (PartNumber) {
$.each(PartNumber, function (i, PartNumber) {
$("#PartNumber").append('<option value="'
+ PartNumber.Value + '">'
+ PartNumber.Text + '</option>');
});
},
error: function (ex) {
alert('Failed.' + ex);
}
});
return false;
})
});
$(document).ready(function () {
$("#Search").click(function () {
$.ajax({
type: 'POST',
url: '#Url.Action("Check","partrequests")',
dataType: 'json',
data: { id: $("#CheckPartNumber").val() },
success: function (Data) {
var selectedValue = Data.PartType
$('#PartType option').map(function () {
if ($(this).val() == selectedValue) return this;
}).attr('selected', 'selected').change();
var selectedValue2 = Data.idParts;
$('#PartNumber option').map(function () {
if ($(this).val() == selectedValue2) return this;
}).attr('selected', 'selected');
},
error: function (ex) {
alert('Failed.' + ex);
}
});
return false;
})
});
</script>

How to update the edited item of knockout js observablearray in UI part?

How to update the knockout js observablearray in UI part..Initially Im editing a item and in update function i'm trying to update a particular item so im sending the current item object to service and getting the updated vales as response. Inside the response I need to update the observablearray as well the UI too.. I have tried some thing like this and its not working for me... please check in http://jsfiddle.net/up8rB/20/
<div data-bind="ifnot: Role()">
<label for="description">Description</label>
<input type="text" data-bind="value: Description" class="form-control" placeholder="Enter the description..." />
<button data-bind="click: $root.create"> Create</button>
</div>
<div data-bind="if: Role">
<label for="description">Description</label>
<input type="text" data-bind="value: Role().Description" class="form-control" placeholder="Enter the description..." />
<button data-bind="click: $root.update"> Save</button>
</div>
<table id="example1" class="table table-bordered table-striped" data-bind="visible: Roles().length > 0">
<thead>
<tr>
<th>RoleID</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody data-bind="foreach: Roles">
<tr>
<td data-bind="text: $data.RoleID"></td>
<td data-bind="text: $data.Description"></td>
<td>
<button data-bind="click: $root.edit" >Edit</button>
<button data-bind="click: $root.delete" >Delete</button>
</td>
</tr>
</tbody>
</table>
function RoleViewModel() {
var self = this;
self.RoleID = ko.observable("0");
self.Description = ko.observable().extend({
required: { message: 'Please supply description ..' }
});
var Role = {
RoleID: self.RoleID,
Description: self.Description
};
self.Role = ko.observable();
self.Roles = ko.observableArray();
$.ajax({
url: 'Service.svc/RoleCollection',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Roles(data); //Put the response in ObservableArray
}
});
self.edit = function (Role) {
self.Role(Role);
}
self.update = function () {
var Role = self.Role();
$.ajax({
url: '..service.svc/UpdateRole',
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Role),
success: function (data) {
for (var i = 0; i < self.Roles().length; i++) {
alert(self.Roles()[i].RoleID());
if (self.Roles()[i].RoleID() === data.RoleID) {
self.Role(self.Roles()[i]);
break;
}
}
}
})
}
var viewModel = new RoleViewModel();
ko.applyBindings(viewModel);
Your issue is that your are assigning items to your observable array that aren't themselves observable, so your UI is not updating when they change.
I did some renaming, as I found it confusing with so many things named 'Role', but the first change was your array setup:
var roles = [{
RoleID: ko.observable(1),
Description: ko.observable('First item')
}, {
RoleID: ko.observable(2),
Description: ko.observable('Second item')
}];
I also modified the update function:
self.update = function () {
var _Role = self.Role();
for (var i = 0; i < self.Roles().length; i++) {
if (self.Roles()[i].RoleID === _Role.RoleID) {
self.Roles()[i] = _Role();
break;
}
}
}
See the Updated Fiddle
Update:
Your json response should populate the observableArray correclty, but you may have an issue when setting it back after the update, try setting the properties rather than overwriting the element:
self.update = function () {
var _Role = self.Role();
for (var i = 0; i < self.Roles().length; i++) {
if (self.Roles()[i].RoleID === _Role.RoleID) {
self.Roles()[i].RoleID = _Role().RoleID;
self.Roles()[i].Description = _Role().Description;
break;
}
}
}
See the Updated Fiddle

Update UI after ajax response

I am new to knocokout.js so i have a table in which data is bind using ajax call.When user click on edit button row information is fill to a form which is on same page below the table.
after ajax call which update the data into database successfully , i am not able to show the changed value of particular object which is changed into table. If i refresh then its show new value .
Here is my html and js code .
<div id="body">
<h2>
Knockout CRUD Operations with ASP.Net Form App</h2>
<h3>
List of Products</h3>
<table id="products1">
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Category
</th>
<th>
Price
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody data-bind="foreach: Products">
<tr>
<td data-bind="text: Id">
</td>
<td data-bind="text: Name">
</td>
<td data-bind="text: Category">
</td>
<td data-bind="text: formatCurrency(Price)">
</td>
<td>
<button data-bind="click: $root.edit">
Edit</button>
<button data-bind="click: $root.delete">
Delete</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
</td>
<td>
</td>
<td>
Total :
</td>
<td data-bind="text: formatCurrency($root.Total())">
</td>
<td>
</td>
</tr>
</tfoot>
</table>
<br />
<div style="border-top: solid 2px #282828; width: 430px; height: 10px">
</div>
<div data-bind="if: Product">
<div>
<h2>
Update Product</h2>
</div>
<div>
<label for="productId" data-bind="visible: false">
ID</label>
<label data-bind="text: Product().Id, visible: false">
</label>
</div>
<div>
<label for="name">
Name</label>
<input data-bind="value: Product().Name" type="text" title="Name" />
</div>
<div>
<label for="category">
Category</label>
<input data-bind="value: Product().Category" type="text" title="Category" />
</div>
<div>
<label for="price">
Price</label>
<input data-bind="value: Product().Price" type="text" title="Price" />
</div>
<br />
<div>
<button data-bind="click: $root.update">
Update</button>
<button data-bind="click: $root.cancel">
Cancel</button>
</div>
</div>
</div>
Code
function formatCurrency(value) {
return "$" + parseFloat(value).toFixed(2);
}
function ProductViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
self.Product = ko.observable();
self.Products = ko.observableArray(); // Contains the list of products
// Initialize the view-model
$.ajax({
url: 'SProduct.aspx/GetAllProducts',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
// debugger;
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
//Put the response in ObservableArray
}
});
// Calculate Total of Price After Initialization
self.Total = ko.computed(function () {
var sum = 0;
var arr = self.Products();
for (var i = 0; i < arr.length; i++) {
sum += arr[i].Price;
}
return sum;
});
// Edit product details
self.edit = function (Product) {
self.Product(Product);
}
// Update product details
self.update = function () {
var Product = self.Product();
$.ajax({
url: 'SProduct.aspx/Update',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: "{Product:" + ko.toJSON(Product) + "}",
success: function (data) {
console.log(data.d);
self.Product(null);
alert("Record Updated Successfully");
},
error: function (data) {
console.log(data);
}
})
}
// Cancel product details
self.cancel = function () {
self.Product(null);
}
}
$(document).ready(function () {
var viewModel = new ProductViewModel();
ko.applyBindings(viewModel);
});
and my webmethod which called by ajax request is as follow :
// to update product
[WebMethod]
public static testModel.Product Update(testModel.Product Product)
{
testEntities db = new testEntities();
var obj = db.Products.First(o => o.Id == Product.Id);
obj.Name = Product.Name;
obj.Price = Product.Price;
obj.Category = Product.Category;
db.SaveChanges();
return obj;
}
and JSON response of ajax call as follow
{"d":{"__type":"testModel.Product","Id":31,"Name":"12","Category":"12","Price":1350,"EntityState":2,"EntityKey":
{"EntitySetName":"Products","EntityContainerName":"testEntities","EntityKeyValues":
[{"Key":"Id","Value":31}],"IsTemporary":false}}}
Here's what's happening. Here: self.Products.push(prd) prd is just a plain javascript object with plain property values, nothing is observable. You're pushing the raw object onto the Products observableArray, which updates the DOM because Products was changed and KO is watching it. When you click 'edit', you set self.Product to that plain object and the KO updates the DOM with this object and its values because Product was changed and KO is watching it. So now your Product form below displays, you see the information, and it looks like you can edit the properties but KO won't update those property changes because KO isn't watching them. They're not observable. Change:
$.each(data.d, function (index, prd) {
//self.Products.push(prd);
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
General helpful tips
<div data-bind="if: Product">
This only evaluates once when you bind the viewModel to the DOM with ko.applyBindings. Since self.Product has an initial value of null KO removes this altogether.*Note: I was thinking of #if for some reason.
This works like the visible binding except when the value is false, the element and its children are removed from the DOM. So there is more DOM manipulation going on than necessary. You probably just want to hide this <div>
I would recommend changing this to:
<div data-bind="visible: Product">
Instead of this:
<input type="text" data-bind="text: Product().Name" />
<input type="text" data-bind="text: Product().Category" />
<input type="text" data-bind="text: Product().Price" />
Try this instead:
<div data-bind="with: Product">
<input type="text" data-bind="text: Name" />
<input type="text" data-bind="text: Category" />
<input type="text" data-bind="text: Price" />
</div>
Consider renaming self.Product to self.SelectedProduct to make it more clear what it is for.
I'm not sure what this is doing in the ViewModel:
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
You don't use them in the DOM. You were kind of on the right path with this though. Instead, before the ProductViewModel, create this:
function ProductModel(data) {
var self = this;
data = data || {};
self.Id = ko.observable(data.Id);
self.Name = ko.observable(data.Name);
self.Price = ko.observable(data.Price);
self.Category = ko.observable(data.Category);
}
Now instead of:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
We can just do this:
$.each(data.d, function (index, prd) {
self.Products.push(new ProductModel(prd));
});
Hopefully that will get you headed in the right direction.
There is something to change:
Replace
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
With:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
})
Use ko.observable to make your properties notify the view of its changes so that the view can update accordingly. This should work but not perfect because this is 2 way binding, so whenever you update the values in your div, the view model object is updated immediately and even if your ajax fails to update the data in backend, making the data out of synch between client side and server side.
For better solution. You need to have a look at protectedObservable
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.protectedObservable(prd.Id),
Name: ko.protectedObservable(prd.Name),
Price: ko.protectedObservable(prd.Price),
Category: ko.protectedObservable(prd.Category)
});
})
Inside your self.update ajax success function, trigger a change:
success: function (data) {
var product =self.Product();
product.Id.commit();
product.Name.commit();
product.Price.commit();
product.Category.commit();
self.Product(null);
alert("Record Updated Successfully");
}
And revert if there is error:
error: function (data) {
product.Id.reset();
product.Name.reset();
product.Price.reset();
product.Category.reset();
}
Update:
Remember to change all the places with Product.Property to Product.Property() to get its property value . For example: arr[i].Price should be changed to arr[i].Price()
Add self.Products.push(data.d); to the update() functions success handler.
success: function (data) {
console.log(data.d);
self.Product(null);
self.Products.push(data.d);
alert("Record Updated Successfully");
},
You need to update the array so that it reflects in bound html.

Cascading select2 Combobox with Knockout JS

Here's the code: http://jsfiddle.net/W4qPT/
the combobox script is included at the bottom, if you remove it, everything works fine.
I cannot seem to get it to refresh the combobox with the new content given to me by the Knockout Ajax.
HTML
<div>
<div class="cbp-content" id="didScreen">
<div>
<table width='100%'>
<thead>
<tr>
<th width='25%'>State</th>
<th width='25%'>City</th>
<th class='quantity' width='10%'>Quantity</th>
<th width='10%'></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td>
<select class="combobox" data-bind="options: $parent.states, optionsText: 'name', value: state, optionsCaption: 'Select State'"></select>
</td>
<td>
<select class="combobox" data-bind="options: cities, optionsText: 'rc_abbr', optionsValue: 'id', value: city"></select>
</td>
<td>
<input name="quantity" data-bind="value: quantity" />
</td>
<td>
<button class="btn" data-bind="click: $parent.remove"><i class="icon-remove"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<button class="btn" data-bind="click: newItem">Add Item</button>
</div>
</div>
</fieldset>
JavaScript (Knockout JS)
var Item = function () {
var self = this;
self.state = ko.observable();
self.city = ko.observable();
self.quantity = ko.observable();
self.cities = ko.observableArray([]);
self.state.subscribe(function (state) {
self.city("");
self.cities.removeAll();
$.ajax({
url: '/echo/json/',
type: 'POST',
data: {
json: ko.toJSON([{"id":"29","rc_abbr":"ANCHORAGE"}]),
},
success: function (response) {
self.cities(response);
}
});
});
};
var ViewModel = function (states) {
var self = this;
self.states = states;
self.items = ko.observableArray([new Item()]);
self.newItem = function () {
self.items.push(new Item());
};
self.remove = function (item) {
self.items.remove(item);
};
};
var usStates = [{
name: 'ALASKA',
abbreviation: 'AK'
}];
window.vm = new ViewModel(usStates);
ko.applyBindings(window.vm, document.getElementById('didScreen'));
$(".combobox").select2();
You have to call .select2() again on all new comboboxes you create. You're now only calling it on comboboxes that exist when your DOM is ready.
You could change this:
self.newItem = function () {
self.items.push(new Item());
};
To this:
self.newItem = function () {
self.items.push(new Item());
$(".combobox").not('.select2-container').select2();
};

Knockout.js: Updation of label element not reflecting in JSON source

I am new to knockout.JS. I am binding a JSON collection to a table.
<tbody data-bind="foreach: Collection">
<tr>
<td>
<span data-bind="text: FirstName" ></span>
</td>
<td>
<span data-bind="text: LastName" ></span>
</td>
<td>
<input type="button" data-bind="click: function(){ obj.RemoveItem($data) }" value="Del" />
</td>
<td>
<input type="button" data-bind="click: function(){ obj.SaveItems($data.Id) }" value="Edit/Save" />
</td>
</tr>
</tbody>
function viewModel(collection) {
var self = this;
this.Collection = ko.observableArray(collection);
this.AddItem = function() {
this.Collection.push({FirstName:"", LastName:""});
};
this.RemoveItem = function(data) {
this.Collection.remove(data);
};
this.SaveItems = function(id) {
alert("New Collection: " + ko.utils.stringifyJson(self.Collection));
}
};
var obj = new viewModel([
{ Id: 1,FirstName: "John", LastName: "Saleth" },
{ Id: 2, FirstName: "John", LastName: "Kennedy" }
]);
ko.applyBindings(obj);
In eachrow, I kept a edit button which on click, inserts a textbox in all TD's with value of
span. And on save click, i am updating the values of span elements with the values of textbox.
The problem is new values of span element is not reflecting in JSON collection. How to update the JSON source with updated span values on click of save button?
You should make each property of the Collection array observable as well.
function ItemModel(item) {
this.Id = ko.observable(item.Id);
this.FirstName = ko.observable(item.FirstName);
this.LastName = ko.observable(item.LastName);
};
function viewModel(collection) {
var self = this;
this.Collection = ko.observableArray();
ko.utils.arrayForEach(collection, function (i) { self.Collection.push(new ItemModel(i)); });
this.AddItem = function() {
this.Collection.push(new ItemModel({
FirstName: "",
LastName: ""
}));
};
...
};

Categories

Resources