Wedad Shurrab Wedad Shurrab - 1 month ago 5
Ajax Question

knockoutjs data bind hidden field value

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">
<a href="#" data-bind="click: function () { openFileUpload('file', ID) }"><label data-bind="text: 'File Upload ' + ID, attr: { id: 'lblFileName' + ID }"></label></a><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) {},
});
};
}

Answer

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.

Comments