Update UI after ajax response - javascript

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.

Related

Manipulating array data to actually save, write, and change the data content

I am new to AngularJS and so far I'm loving it but I am having a hard time manipulating my data with it. I have an array of data with the attributes name:'', description:'', type:'', ... etc ... and I have enough data but not enough yet for me to upload it onto a server. My problem is that I want to be able to change and update my data using a form or input.
Here is my scripts/admin.js where I implement function submitTheForm() that I call with the submit button.
angular.module('myApp')
//filter to get a specific $scope.campaigns using its id
.filter('getById', function() {
return function(input, id) {
var i=0, len=input.length;
// alert(input.length);
for (; i<len; i++) {
if (+input[i].id === +id) {
return input[i];
}
}
return input[0];
};
})
.controller('AdminCtrl', ['$scope', '$filter', function($scope, $filter) {
//<--ARRAY OF DATA with multiple attributes<--
$scope.campaigns = [
{ name:'', description'', etc... etc...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
];
$scope.selectCampaign = function(object) {
$scope.selectedCampaign = object;
};
$scope.submitTheForm = function(item, event) {
if (confirm("Are you sure you want to edit?") == true) {
alert("--> Submitting form");
var dataObject = {
name : $scope.selectedCampaign.name, description: $scope.selectedCampaign.description, type: $scope.selectedCampaign.type, imgSrc: $scope.selectedCampaign.imgSrc, brand: $scope.selectedCampaign.brand, region: $scope.selectedCampaign.region, location: $scope.selectedCampaign.location, contact: $scope.selectedCampaign.contact, url: $scope.selectedCampaign.url, id: $scope.selectedCampaign.id
};
console.log(dataObject);
var campaign = $scope.selectedCampaign;
var id = campaign.id;
var found = $filter('getById')($scope.campaigns, id);
// setTimeout(function(){ $scope.$apply($scope.selectedCampaign = dataObject); });
}
};
}]);
Here is my main.html where I have my input and submit button
<div class="row modalDetail">
<div class="col-xs-12 col-sm-6 col-md-6 detailLeft text-left">
<div class="middle-allign">
<h1 class="detailName">
<input type="text" ng-model="selectedCampaign.name" name="name">
</h1>
<div class="detailDescription">
<textarea rows="5" cols="71" name="description" ng-model="selectedCampaign.description"></textarea>
</div>
<table class="detailTable table">
<tbody>
<tr>
<td class="bolder">Brand</td>
<td>
<input type="text" ng-model="selectedCampaign.brand" name="brand" >
</td>
</tr>
<tr>
<td class="bolder">Campaign Type</td>
<td>
<input type="text" ng-model="selectedCampaign.type" name="type">
</td>
</tr><tr>
<td class="bolder">Region</td>
<td>
<input type="text" ng-model="selectedCampaign.region" name="region">
</td>
</tr>
<tr>
<td class="bolder">Contact</td>
<td>
<input type="text" ng-model="selectedCampaign.contact" name="contact">
</td>
</tr>
<tr>
<td class="bolder">Location</td>
<td>
<input type="text" ng-model="selectedCampaign.location" name="location">
</td>
</tr>
<tr>
<td class="bolder">URL</td>
<td>
<input type="text" ng-model="selectedCampaign.url" name="url">
</td>
</tr>
</tbody>
</table>
<div class="detailCta">
<button class="btn detailButton" ng-click="submitTheForm()">Submit Campaign</button>
</div>
</div>
</div>
I am trying to utilize 'ng-model' to bind the data and it all works fine but it does not actually change the array content within my main.html. When I refresh it all just goes back to how my array content is. This is because I haven't actually over-written my array content. How can I go about making a absolute change/over-write to the actual object within the array content?
I feel as though it is as simple as $scope.campaigns.push(campaign); except instead of 'push' it would be 'update' or 'over-write'
If you want to store the values in the server, you should see ngResource to create entry points to get and save (and delete) data. Alternatively, you can use the lower level service $http.
If you want to store the data in your current script (it will last until the page is refreshed in the browser - F5), you should do some changes:
.controller('AdminCtrl', ['$scope', '$filter', '$rootScope', function($scope, $filter, $rootScope) {
//<--ARRAY OF DATA with multiple attributes<--
if ($rootScope.campaigns === undefined) {
$rootScope.campaigns = [
{ name:'', description'', etc... etc...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
];
}
$scope.campaigns = $rootScope.campaigns;
//don't even think this above line is needed, since $scope inherits from $rootScope, but I've put it for clarity.
$scope.selectCampaign = function(object) {
$scope.selectedCampaign = object;
};
$scope.submitTheForm = function(item, event) {
if (confirm("Are you sure you want to edit?") == true) {
alert("--> Submitting form");
var dataObject = {
name : $scope.selectedCampaign.name, description: $scope.selectedCampaign.description, type: $scope.selectedCampaign.type, imgSrc: $scope.selectedCampaign.imgSrc, brand: $scope.selectedCampaign.brand, region: $scope.selectedCampaign.region, location: $scope.selectedCampaign.location, contact: $scope.selectedCampaign.contact, url: $scope.selectedCampaign.url, id: $scope.selectedCampaign.id
};
console.log(dataObject);
var campaign = $scope.selectedCampaign;
var id = campaign.id;
var found = $filter('getById')($scope.campaigns, id);
}
};
}]);
Notice how I bind it to $rootScope.campaigns - so if you navigate to another ng-view and then come back, the data is still here.
However, if you want your data survive the F5, you must either use the server side options I gave you. or use Local Storage.

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

Focus input added dynamically to observableArray in knockout

In KO 3.0.0.beta (and I am almost sure it'd be the same in 2.3) I am trying to add new row to a dynamically created table:
HTML
<div id="root">
<table>
<tbody data-bind="foreach: events">
<tr>
<td>
<input type="text" data-type="name" data-bind="value: name, css: {hidden: !editing()}, hasFocus: true">
</td>
<td>
<input type="text" data-type="method" data-bind="value: age, css: {hidden: !editing()}">
</td>
</tr>
</tbody>
</table>
</div>
JavaScript
var $root = $('#root');
$root.on('blur', 'table input', function(event) {
var data = ko.dataFor(event.target),
context = ko.contextFor(event.target),
$input = $(event.target),
newData;
data.editing(false);
if($input.closest('td').is(':last-child') && $input.closest('tr').is(':last-child')) {
newData = {
name: '',
age: '',
editing: ko.observable(false)
};
context.$root.events.push(newData);
newData.editing(true);
}
});
var data = {
events: [
{name: 'aaa', age: '22', editing: false},
{name: 'bbb', age: '33', editing: false},
{name: 'ccc', age: '44', editing: false}
]
};
var mapping = {
events: {
key: function(data) {
return ko.unwrap(data.name);
}
}
};
var observable = ko.mapping.fromJS(data, mapping);
ko.applyBindings(observable, $root[0]);
JSFiddle
and it almost works.
I am successful with row creation - which was the siple part, but for the life of me I can't make the first input in the created raw to be focused.
Any ideas (and I went through a ton of suggestions, none of which worked in the above setting)?
I might be missing the point, but why not just set your hasFocus to editing() instead of true?
<div id="root">
<table>
<tbody data-bind="foreach: events">
<tr>
<td>
<input type="text" data-type="name" data-bind="value: name, css: {hidden: !editing()}, hasFocus: editing()">
</td>
<td>
<input type="text" data-type="method" data-bind="value: age, css: {hidden: !editing()}">
</td>
</tr>
</tbody>
</table>
</div>
Fiddle here
It often pays of to avoid mixing jQuery with Knockout like that. For most cases Knockout also has options. In your case, the ones to look at are the event binding and the hasFocus binding.
Looking at your code, I'd update the View to something like this:
<tr>
<td>
<input type="text" data-bind="value: name,
hasFocus: editingName">
</td>
<td>
<input type="text" data-bind="value: age,
hasFocus: editingAge,
event: { blur: $root.onBlurAgeEdit }">
</td>
</tr>
As an aside, if you're after "MS Word Style" creation of new rows when a user presses tab, you can also bind to the "keypress" event and check for the correct keycode (for tab).
Notice that I've split the editing observable in two observables: editingName and editingAge.
The function onBlurAgeEdit will fire whenever the age input blurs. It looks like this:
self.onBlurAgeEdit = function (item) {
// Unwrap the array
var myEvents = self.events();
// Check if this function was called for the *last* item in the array
if (myEvents[myEvents.length-1] === item) {
// Make sure the last item isn't in edit mode anymore
item.editingAge(false);
// Push a new item that has *name* in edit mode
self.events.push({name: ko.observable(''),
age: ko.observable(''),
editingName: ko.observable(true),
editingAge: ko.observable(false)});
}
};
Note that for Firefox you'll need to throttle the observables to make the hasFocus binding play nice.
See all this at work in this fiddle.

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