knockoutjs data bind hidden field value - ajax

I'm having a hidden field in a knockout template that its value gets updated with jquery. The problem is when trying to pass this value to the server with ajax, I get null value in the controller. But the html source code shows that the value of the hidden field is updated. If I replaced the hidden field with a textbox, it would work fine only when I enter text manually.
jQuery
function getFileDetail(fileID, fileName) {
$('#hdnFileName' + fileID).val(fileName);
$('#lblFileName' + fileID).text(fileName);
}
Here is the html knockout template:
<script type="text/html" id="fileTemplate">
<div data-role="fieldcontain">
<label data-bind="text: 'File Upload ' + ID, attr: { id: 'lblFileName' + ID }"></label><input type="button" value="Remove" data-bind="click: removeFile" />
</div>
<input type="hidden" name="hdnFileName" data-bind="attr: { id: 'hdnFileName' + ID, value: fileName }" />
</script>
ViewModel
function FileViewModel() {
var self = this;
self.ID = ko.observable();
self.fileName = ko.observable();
self.removeFile = function (file) { };
self.Files = ko.observableArray([{ ID: 1, fileName: "", removeFile: function (file) { self.Files.remove(file); }}]);
self.addNewFile = function () {
var newFile = new FileViewModel();
newFile.ID = self.Files().length + 1;
newFile.fileName = "";
newFile.removeFile = function (file) { self.Files.remove(file); };
self.Files.push(newFile);
//$("input[name='hdnFileName'").trigger("change");
}
}
function ViewModel() {
var self = this;
self.fileViewModel = new FileViewModel();
self.submitForm = function () {
$.ajax({
type: "POST",
url: "<%= Url.Action("MeetingPresenter")%>",
data: "{Files:" + ko.utils.stringifyJson(self.fileViewModel.Files) + "}",
contentType: "application/json",
success: function (data) {},
});
};
}

Your model property ID is an observable, so you need to 'unwrap' to get the value from it when you are concatenating, like this:
<input type="hidden" name="hdnFileName" data-bind="attr: { id: 'hdnFileName' + ID(), value: fileName }" />
and this:
<label data-bind="text: 'File Upload ' + ID(), attr: { id: 'lblFileName' + ID() }"></label>

If you are using knockout.js you don't neede to modify the DOM, you can just update the ViewModel and the DOM will be updated according
function getFileDetail(fileID, fileName) {
viewModel.fileViewModel.update(fileID, fileName);
}
Add the update function in FileViewModel
function FileViewModel() {
// rest of the code
self.update = function(fileID, fileName) {
var file = ko.utils.arrayFirst(self.Files(), function(file) {
return file.ID == fileID;
});
file.fileName(fileName); // this will change and the UI will be updated according
};
}
Note: Please notice that you have a default item in Files that will not be changed with update function because properties are not observable
self.Files = ko.observableArray([{ ID: 1, fileName: "", removeFile: function (file) { self.Files.remove(file); }}]);
You can solve this by making them observable (i.e. ID: observable(1)) or you can create a new FileViewModel().
Note: The viewModel must be accesible in the function (i.e. global instance), otherwise will be undefined.

It looks to me that setting a field's value via the DOM does not interact with knockout. If you are setting its value using .value, the observable will not be updated. You should be updating the observable.
I wrote a little Fiddle to demonstrate. Every 2 seconds, it sets the input's value via the DOM, but the bound observable only changes when you type something.
http://jsfiddle.net/qcv01h2e/
var viewModel = (function () {
return {
fv: ko.observable().extend({notify:'always'})
};
}());
ko.applyBindings(viewModel);
setInterval(function () {
console.debug("Set it");
var f = document.getElementById('field');
f.value = "Hi";
console.debug("fv is", viewModel.fv());
}, 2000);

I came across a similar issue where I need to set a value without user input.
Before doing the click update function I do the required model update. If you have mode operations better to introduce a function in the model.
<input data-bind="click: function(){ isEnabled(true); update() }" />
What I actually did was,
<input data-bind="click: function(){ isEnabled(!isEnabled()); update() }" />
Keep in mind that asynchronous nature of javascript.

Related

Pushing array to select in knockout gives just one option

I am using MVC and a Razor View I'm trying to bound data received from a controller to a select using a knockout model, If I try to push directly the dynamic array I get only one option like this one
Only one option select:
I'm sure that I'm missing something stupid, I have already tried to return a new SelectList and using optionsText and optionsValue but didn't do the work.
I'm sure the knockout model is correct because if I write
viewModel.dliveryDates.push("option1","option2");
it works as expected
Here's my controller code that reads some data from database and send it back to the view
[HttpPost]
public JsonResult GetDeliveryDates(string code)
{
OrderHeaderPageModel instance = ObjectFactory.Create<OrderHeaderPageModel>();
instance.DeliveryDateRanges = PopulateDeliveryDateRanges(code);
return Json(instance.DeliveryDateRanges.ToArray());
}
Here's is my View code
#Html.DropDownList("deliveryranges", new SelectList(string.Empty, "Code", "Description"), "- Seleziona -", new { #data_bind = "options:dliveryDates" })
And finally my knockout model
function OrderHeaderViewModel() {
var self = this;
self.save = function () {
return true;
}
self.dliveryDates = ko.observableArray([]);
}
var viewModel = new OrderHeaderViewModel();
ko.applyBindings(viewModel, el);
$("#ordertypes").change(function () {
var postUrl = "/checkout/getdeliverydates";
$("#deliveryranges").empty();
$.post(postUrl,
{
code: $("#ordertypes").val(),
__RequestVerificationToken: Sana.Utils.getAntiForgeryToken()
}, function (data) {
var arry = [];
var array = $.map(data, function (value, index) {
return [value];
});
$.each(data, function (i, data) {
arry.push(data.Code);
});
viewModel.dliveryDates.push(arry);
}
);
})
It looks like the code is doing some extra work mapping data that is not used in the ajax callback. Hope the following code helps.
function OrderHeaderViewModel() {
var self = this;
self.getData = function() {
//function to simulate filling the array from the server.
var data = ["Item 1", "Item 2", "Item 3", "Item 4"];
self.dliveryDates(data);
var mappedData = data.map(function(item, index) {
return {
id: index,
description: item
};
});
viewModel.mappedDliveryDates(mappedData);
}
self.save = function() {
return true;
}
//added to put the selected values in
self.selectedValue = ko.observable();
self.selectedMappedValue = ko.observable();
self.mappedDliveryDates = ko.observableArray([]);
self.dliveryDates = ko.observableArray([]);
}
var viewModel = new OrderHeaderViewModel();
ko.applyBindings(viewModel);
$("#ordertypes").change(function() {
var postUrl = "/checkout/getdeliverydates";
$("#deliveryranges").empty();
$.post(postUrl, {
code: $("#ordertypes").val(),
__RequestVerificationToken: Sana.Utils.getAntiForgeryToken()
}, function(data) {
// if the data needs to be transformed and is already an array then you can use
var mappedData = data.map(function(item, index) {
return {
id: index,
description: item
};
});
// If the data is already in the format that you need then just put it into the observable array;
viewModel.mappedDliveryDates(mappedData);
viewModel.dliveryDates(data);
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Server Data Values -
<select data-bind="options: dliveryDates, value:selectedValue, optionCaption: 'Choose...'"></select>
<br/> Mapped Values -
<select data-bind="options: mappedDliveryDates, optionsText:'description', value: selectedMappedValue, optionCaption: 'Choose...'"></select>
<br/>
<button data-bind="click: getData">Load Data</button>
<br/>
<br/>
<pre data-bind="text: ko.toJSON($root)"></pre>

how to load a partial view inside an anchor tag which has been generated via Ajax

I have a form with a dropdownlist. When selecting an option, I make an ajax call to dynamically add a list of links in the view. When I click on one of the links, I want to update the existing page with a partial view returned by the PostListSubCategory() method.
Currently, clicking on one of the links does a redirect and shows the partial view in a new page. How can I update the the existing page?
<script language="javascript" type="text/javascript">
function GetSubCategory(_categoryId) {
var procemessage = "<a='0'> Please wait...</a>";
$("#SubCategoryID").html(procemessage).show();
var url = "/Posts/GetSubCategoryById/";
$.ajax({
url: url,
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
var markup = "";
for (var x = 0; x < data.length; x++) {
var num = data[x].Text;
markup += "<a href='/posts/postlistsubcategory?subcategoryid=" + data[x].Text + "'>" + data[x].Text + "</a><br />";
// markup += "<a href=" + Url.Action("postlistsubcategory", new { subcategoryid = num });
}
$("#SubCategoryID").html(markup).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
$.ajax({
url: "/Posts/PostListCategory",
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
$("#postList").html(data).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
#using (Html.BeginForm())
{
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel, "CategoryId", "Name"), new { #id = "ddlcategory", #style = "width:200px;", #onchange = "javascript:GetSubCategory(this.value);" })
<br />
<br />
<div id="SubCategoryID" name="SubCategoryID" style="width: 200px"></div>
<br /><br />
}
In the controller
public PartialViewResult PostListSubCategory(string subcategoryid)
{
if (subcategoryid == null)
{
return PartialView(db.Posts.ToList());
}
return PartialView("PostList", db.Posts.Include(i => i.SubCategory).Where(p => p.SubCategory.Name == subcategoryid));
}
You currently dyamically generating links with an href attribute so clicking on them will do a redirect. You need to handle the click event of those links using event delegation and then use ajax to update the existing DOM. There a some other bad practices in your code and I suggest you use the following
#using (Html.BeginForm())
{
// no need to override the id attribute and use Unobtrusive Javascript (don't pollute markup with behavior)
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel,"CategoryId", "Name"))
}
<div id="SubCategoryID"></div> // no point adding a name attribute
<div id="postList"></div>
var subcategories = $('#SubCategoryID');
$('#CategoryModel').change(function() {
var url = '#Url.Action("GetSubCategoryById", "Posts")'; // don't hard code url's
var category = $(this).val();
subcategories.empty(); // clear any existing links
$.post(url, { categoryid: category }, function(data) { // this could be a GET?
$.each(data, function(index, item) {
subcategories.append($('<a></a>').text(item).attr('href','#').addClass('subcategory')); // see note below
});
});
});
Note: Since your ajax only needs one property to generate the links (the value to display in the link), then your GetSubCategoryById() should be returning IEnumerable<string> not a collection of complex objects (you current code suggest your returning other data which you never use). If you do need to return a collection of objects, then change the above to use .text(item.Text). The above code will generate
.....
for each item you return. Then add an additional script to handle the .click() event of the links (since the links are dynamically added, you need event delegation using the .on() method)
var posts = $('#postList');
$('#SubCategoryID').on('click', '.subcategory', function() {
var url = '#Url.Action("postlistsubcategory", "posts")';
var subcategory = $(this).text();
posts.load(url, { subcategoryid: subcategory });
});

knockout computed not updating while change in view model being made from ajax

How much I know about knockout Js is that a computed gets updated anyhow depending on the viewmodel, but in my case its not happening. So basically I have a radio button which turns off and on and changes the date in the database, and the ajax calls returns and pushes the new date in the viewmodel so that the data changes.
So thats the summary. But the thing I want is that while the radio button is being updated I want a part of the html to change to active or disabled based on the radio button.
Firstly here is the HTML code.
<div class="col-sm-4">
<p>
<span data-bind="text : $data.basketStatusValue"></span>
</p>
</div>
<div class="col-sm-4">
<div class="on_off">
<input type="checkbox" data-bind="bootstrapSwitchOn: {
tocall: $root.changeActiveBasketStatus
}" />
</div>
</div>
Here is the JS code.
function MoneyInvestedViewModel(root /* root not needed */, money) {
var self = this;
self.ID = money.ID;
self.ORIG_ID = money.ORIG_ID;
self.Available = money.Available;
self.basketStatusValue = ko.computed (function () {
if (self.Available == '9999-12-01') {
return "Active";
} else {
return "Disabled";
}
});
};
And next is the code which is updating the view model moneyInvested . So the checkbox can show on or off.
self.changeActiveBasketStatus = function (bindingContext) {
console.log(bindingContext);
var Id = bindingContext.$data.ORIG_ID;
var Available = bindingContext.$data.Available;
if (Available == '9999-12-01') {
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + Id + "/" + 1,
contentType: 'application/json; charset=utf-8'
})
.done(function (newAvailableDate) {
bindingContext.$data.Available = newAvailableDate;
})
.fail(function (jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
})
.always(function (data){
});
} else {
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + Id + "/" + 0,
contentType: 'application/json; charset=utf-8'
})
.done(function (newAvailableDate) {
bindingContext.$data.Available = newAvailableDate;
})
.fail(function (jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
})
.always(function (data) {
});
}
};
So basically the PROBLEM is that when all this update is done, the computed self.basketStatusValue does not get updated. So when I click the checkbox on, it doesnt show Active, or off for disabled, the checkbox is working perfectly, only the html $data.basketStatusValue is not updating through the computed function.
Just incase if necessary here is the code for the checkbox.
(function ($) {
ko.bindingHandlers.bootstrapSwitchOn = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.utils.unwrapObservable(valueAccessor());
var tocall = ko.utils.unwrapObservable(options.tocall);
$elem = $(element);
$(element).bootstrapSwitch();
$(element).bootstrapSwitch('setState', bindingContext.$data.Available === '9999-12-01' ? true : false); // Set intial state
$elem.on('switch-change', function (e, data) {
tocall(bindingContext);
// valueAccessor()(data.value);
});
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
}
};
})(jQuery);
To summarize, all I want to do is have the $data.basketStatusValue have "active" or "disabled" when the checkbox is on or off.
A dirty trick you can use to pull this off is empty the whole observable and push it with the new data. But honestly its not the right way to use it. I am assuming right now thats its a array, but you can remove observables too. Just put the observable name instead of YourArray().
self.refresh = function(){
var data = YourArray().slice(0);
YourArray.removeAll();
self.YourArray(data);
};
And place this function right after the done function
.done(function(newAvailableDate) {
bindingContext.$data.Available = newAvailableDate;
// here self.refresh();
})
Your binding handler is wrong, let's start with that.
It should:
Set up Bootstrap switch on the element in init()
React to change in update()
Bind to an observabe (don't use a callback function). In our case the observable should contain the checkbox state, i.e. true or false.
Properly dispose of the Bootstrap widget when the time comes.
So, this would work better:
(function ($) {
ko.bindingHandlers.bootstrapSwitch = {
init: function (element, valueAccessor) {
var options = valueAccessor();
// set up bootstrap in init()
$(element).bootstrapSwitch().on('switch-change', function (e, data) {
options.value(data.value);
});
// see http://knockoutjs.com/documentation/custom-bindings-disposal.html
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).bootstrapSwitch("destroy");
});
},
update: function(element, valueAccessor) {
var options = valueAccessor();
// react to change in update()
$(element).bootstrapSwitch('setState', options.value());
}
};
})(jQuery);
Next we need to set up the viewmodel accordingly.
Available needs to be observable. View changes depend on it.
we need an observable that returns true or false, depending on Available
we need an observable that returns "Active" or "Disabled", depending on that
we need a function that updates the server on change (through a subscription)
like this:
function MoneyInvestedViewModel(money) {
var self = this;
self.ID = money.ID;
self.ORIG_ID = money.ORIG_ID;
self.Available = ko.observable(money.Available);
self.errorMessage = ko.observable();
self.BasketStatus = ko.computed(function () {
return self.Available() == '9999-12-01';
});
self.BasketStatusText = ko.computed(function () {
return self.basketStatus() ? "Active" : "Disabled";
});
// BEWARE: this is not actually correct (cicular dependency)
self.BasketStatus.subscribe(function () {
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + self.ID + "/" + 1,
contentType: 'application/json; charset=utf-8'
})
.done(function (newAvailableDate) {
self.Available(newAvailableDate);
})
.fail(function (jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
});
};
}
Note: Subscribe to the correct observable to update the server with the proper value. It was not clear from your question what value the server update depends on.
And now it's straightforward to bind a view to that:
<div class="col-sm-4">
<p><span data-bind="text: BasketStatusText"></span></p>
</div>
<div class="col-sm-4">
<div class="on_off">
<input type="checkbox" data-bind="bootstrapSwitch: {
value: BasketStatus
}" />
</div>
</div>
if(self.Available == '9999-12-01'){ return "Active"; }else{ return "Disabled";}
The trouble with this line is that it does not look up the value of any observable or computed, and thus it does not cause the computed to ever be updated.
You need to make self.Available an observable and then do self.Available()
This is how computeds work, they are recomputed when any of their observable/computed dependencies change. Knockout will not see a simple property update like you are doing.

Modify Content in valums file upload plugins after completion of upload

I am using Valums ajax file-upload plugins for multi file-upload using asp.net mvc 3.
Views
#using (Html.BeginForm("Upload", "AjaxUpload", FormMethod.Post, new { name = "form1", #id="form1" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Upload Wav File</legend>
<div class="editor-label">
#Html.Label("Select Active Date Time")
</div>
<div>
<input type="text" id="active" value="#DateTime.Now" />
</div>
<div class="editor-label">
#Html.Label("Select Language")
</div>
<div>
#Html.DropDownList("Language1", (SelectList)ViewBag.lang)
</div>
<div class="editor-label">
#Html.Label("Select Category")
</div>
<div>
#Html.DropDownList("ParentCategoryID", ViewBag.ParentCategoryID as SelectList)
</div>
<br />
<div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
</fieldset>
}
Scripts
<script type="text/javascript">
var uploader = new qq.FileUploader
({
element: document.getElementById('file-uploader'),
onSubmit: function () {
uploader.setParams({
param1: document.getElementById("Language1").value,
param2: document.getElementById("ParentCategoryID").value,
param3: document.getElementById("active").value
});
},
action: '#Url.Action("upload")', // put here a path to your page to handle uploading
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // user this if you want to upload only pictures
sizeLimit: 4000000, // max size, about 4MB
minSizeLimit: 0, // min size
debug: true
});
</script>
Controller Action
[HttpPost]
public ActionResult Upload(HttpPostedFileBase qqfile, string param1, string param2, string param3)
{
var filenam = DateTime.Now.ToString("yyyyMMddhhmmss") + param1 + param2 + Request["qqfile"];
var filename = filenam.Replace(" ", "_");
var filepath = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(filename));
if (param2 != null || param2 != "")
{
var wav = new PlayWav
{
Name = filename,
CategoryID = int.Parse(param2),
UserID = repository.GetUserID(HttpContext.User.Identity.Name),
LanguageID = int.Parse(param1),
UploadDateTime = DateTime.Now,
ActiveDateTime = DateTime.Parse(param3),
FilePath = filepath
};
db.AddToPlayWavs(wav);
if (qqfile != null)
{
qqfile.SaveAs(filepath);
db.SaveChanges();
return Json(new { success = true }, "text/html");
}
else
{
if (!string.IsNullOrEmpty(filepath))
{
using (var output = System.IO.File.Create(filepath))
{
Request.InputStream.CopyTo(output);
}
db.SaveChanges();
return Json(new { success = true });
}
}
}
return Json(new { success = false });
}
Problems Explaination
I have Upload controller action where I have rename the filename for uploaded file and it is working fine. The problem here is that after file is uploaded, file name displayed the name of original file name and also show the file size. But I want to display the file name which is re-named and the value which is selected in dropdown box list and datetime value submitted from form fields and it's file size is ok. I have no idea how could I modify those content which is displayed after file-upload is completed.
First the new file name is to be returned to clienside as,
assuming filename to be shown is already yielded in the following line,
var filenam = DateTime.Now.ToString("yyyyMMddhhmmss")
+ param1 + param2 + Request["qqfile"];
this needs to be sent to client side,
return Json(new { success = true, filename });
client side code changes, notice the onCompleted event handler, its job is to replace the original filename with the new one received from server.
<script type="text/javascript">
var uploader = new qq.FileUploader
({
element: document.getElementById('file-uploader'),
onSubmit: function () {
uploader.setParams({
param1: document.getElementById("Language1").value,
param2: document.getElementById("ParentCategoryID").value,
param3: document.getElementById("active").value
});
},
onComplete: function (id, fileName, responseJson) {
$(this.element).find('.qq-upload-list li[qqFileId=' + id + ']').find('.qq-upload-file').html(responseJson.filename);
},
action: '#Url.Action("upload")', // put here a path to your page to handle uploading
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // user this if you want to upload only pictures
sizeLimit: 4000000, // max size, about 4MB
minSizeLimit: 0, // min size
debug: true
});
</script>
hope this helps.
EDIT:
qqFileId attribute in the li element is the only associating link bitween the informative li item and uploaded files.
Though the qqFileId is not visible in firebug dom structure, in the console executing the following command shows the id,
$('.qq-upload-list li:last').attr('qqFileId')
if ie browser is causing you the problem it might be because of,
find('.qq-upload-list li[qqFileId=' + id + ']')
and can be changed as
onComplete: function (id, fileName, responseJson) {
$(this.element).find('.qq-upload-list li').each(function () {
if($(this).attr('qqFileId')==id)
$(this).find('.qq-upload-file').html(responseJson.filename);
});
}

Cannot bind JSon with MVC 3 controller data using KnockoutJS

I am new to javascript and MVC 3. I am developing a sample application to get familiar with KnockoutJs.
I am passing a c# object with some properties to a controller. Than this object is passed to the View serialized as JSon. Then I am using the data with Knockout in my view and want to return this data back to the server. But the binding with the the server data fails for on of my properties.
Here is my code:
Model:
public class FranchiseInfo
{
public string FullName { get; set; }
public string ShortName { get; set; }
public List<string> ServerIps = new List<string>();
}
Controller with sample data returning JSon to the View:
public JsonResult Data()
{
FranchiseInfo franchiseInfo = new FranchiseInfo();
franchiseInfo.FullName = "PokerWorld";
franchiseInfo.ShortName = "PW";
franchiseInfo.ServerIps.Add("192.111.1.3");
franchiseInfo.ServerIps.Add("192.112.1.4");
return Json(franchiseInfo, JsonRequestBehavior.AllowGet);
}
Javascript file using knockout:
$(function () {
function viewModel() {
var self = this;
self.FullName = ko.observable();
self.ShortName = ko.observable();
self.optionValues = ko.observableArray([]);
self.ServerIps = ko.observableArray([]);
$.getJSON("Home/Data", function (data) {
self.FullName(data.FullName);
self.ShortName(data.ShortName);
self.optionValues([data.FullName, data.ShortName]);
for (var i = 0; i < data.ServerIps.length; i++) {
self.ServerIps.push({ name: ko.observable(data.ServerIps[i]) });
}
});
self.addIp = function () {
self.ServerIps.push({ name: ko.observable("0.0.0") });
}
self.showIps = function () {
alert(self.ServerIps[name]);
}
self.save = function () {
$.ajax({
url: "Home/Save",
type: "post",
data: ko.toJSON({ FullName: self.FullName, ShortName: self.ShortName, ServerIps: self.ServerIp }),
contentType: "application/json",
success: function (result) { alert("result") }
});
}
};
ko.applyBindings(new viewModel);
View:
Full Name:
<span data-bind="text: FullName"></span>
<input data-bind="value: FullName" />
</div>
<div>
Short Name:
<span data-bind="text: ShortName"></span>
</div>
<select data-bind="options: optionValues"></select>
<div data-bind="foreach: ServerIps">
Name:
<input data-bind="value: name" />
<span data-bind="text: name" />
</div>
<div data-bind="text: ko.toJSON(ServerIps)"></div>
<button data-bind="click: addIp">Add IP</button>
<button data-bind="click: save">Save</button>
When Save button is clicked the data is sent to the server in Json format:
Here is the controller:
public JsonResult Save(FranchiseInfo franchiseInfo)
{
//some data here
//return Json result
}
Full name and Short name properties bind correctly with the c# model when I am sending them in Json format back to the server but the ServerIps property which is an array cannot bind. I think because it is in the format { name: ip} and the model property ServerIps is of type List. How can I fix this ? Any help with working example will be appreciated. Thanks.
I had the same problem in Java Spring.
We solved it by serializing the ViewModel as a request string.
We wrote the function ourselves (although you might want to check if the 'value' is an array and go a bit recursive):
function serializeViewModelToPost(dataString) {
var data = ko.toJS(dataString);
var returnValue = '';
$.each(data, function (key, value) {
returnValue += key + '=' + value + '&';
});
return returnValue;
}
Another option is to parse it serverside:
link
UPDATE:
self.save = function () {
$.ajax({
url: "Home/Save",
type: "post",
data: serializeViewModelToPost(this)),
success: function (result) { alert("result") }
});
You still need to edit the serialize function to check for arrays.

Resources