I have this knockout js script for uploading file
This code triggers the upload event when the user selects a file in the upload control
Upload.html
$(function() {
var viewModel = {
filename: ko.observable(""),
};
ko.applyBindings(viewModel);
});
<form>
<input id="upload" name="upload"
data-bind="fileUpload: { property: 'filename', url: 'http://localhost/api/upload/PostFormData' }"
type="file" />
<button id="submitUpload">Upload</button>
</form>
FileUpload.js
ko.bindingHandlers.fileUpload = {
init: function (element, valueAccessor) {
$(element).after('<div class="progress"><div class="bar"></div><div class="percent">0%</div></div><div class="progressError"></div>');
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.utils.unwrapObservable(valueAccessor()),
property = ko.utils.unwrapObservable(options.property),
url = ko.utils.unwrapObservable(options.url);
if (property && url) {
$(element).change(function() {
if (element.files.length) {
var $this = $(this),
fileName = $this.val();
// this uses jquery.form.js plugin
$(element.form).ajaxSubmit({
url: url,
type: "POST",
dataType: "text",
headers: { "Content-Disposition": "attachment; filename=" + fileName },
beforeSubmit: function() {
$(".progress").show();
$(".progressError").hide();
$(".bar").width("0%")
$(".percent").html("0%");
},
uploadProgress: function(event, position, total, percentComplete) {
var percentVal = percentComplete + "%";
$(".bar").width(percentVal)
$(".percent").html(percentVal);
},
success: function(data) {
//$(".progress").hide();
//$(".progressError").hide();
// set viewModel property to filename
$("label[for='upload']").text(data);
bindingContext.$data[property](data);
},
error: function(jqXHR, errorThrown) {
$(".progress").hide();
$("div.progressError").html(jqXHR.responseText);
}
});
}
});
}
}
}
Now, I want to move the triggering of upload event to the submit button
<button id="submitUpload">Upload</button>
How to do this? Right now this is where I'm at, I just move the upload event inside the click event of the button. But it's not working, and it doesn't call the ajax request to the API.
$('#submitUpload').click(function () {
if (element.files.length) {
var $this = $(element),
fileName = $this.val();
//alert(element.form);
// this uses jquery.form.js plugin
$(element.form).ajaxSubmit({
url: url,
type: "POST",
dataType: "text",
headers: { "Content-Disposition": "attachment; filename=" + fileName },
beforeSubmit: function() {
$(".progress").show();
$(".progressError").hide();
$(".bar").width("0%")
$(".percent").html("0%");
},
uploadProgress: function(event, position, total, percentComplete) {
var percentVal = percentComplete + "%";
$(".bar").width(percentVal)
$(".percent").html(percentVal);
},
success: function(data) {
//$(".progress").hide();
//$(".progressError").hide();
// set viewModel property to filename
$("label[for='upload']").text(data);
bindingContext.$data[property](data);
},
error: function(jqXHR, errorThrown) {
$(".progress").hide();
$("div.progressError").html(jqXHR.responseText);
}
});
}
});
Instead of passing only name, URL to the bindinghandler pass third parameter (fileBinaryData) from your ViewModel Object then read the file Content in KO BindingHandler's Update method then update third observable (fileBinaryData) in update method.
Then you can use this filebinary data in you viewmodel
so for the button bind click event and access fileBinaryData observable which will have the file content.
BindingHandler:
ko.bindingHandlers.FileUpload = {
init: function (element, valueAccessor) {
$(element).change(function () {
var file = this.files[0];
if (ko.isObservable(valueAccessor())) {
valueAccessor()(file);
}
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var file = ko.utils.unwrapObservable(valueAccessor());
var bindings = allBindingsAccessor();
if (bindings.fileBinaryData && ko.isObservable(bindings.fileBinaryData)) {
if (!file) {
bindings.fileBinaryData(null);
} else {
var reader = new window.FileReader();
reader.onload = function (e) {
bindings.fileBinaryData(e.target.result);
};
reader.readAsBinaryString(file);
}
}
}
}
HTML:
<input type="file" id="fileUpload" class="file_input_hidden" data-bind="FileUpload: spFile, fileObjectURL: spFileObjectURL, fileBinaryData: spFileBinary" />
ViewModel:
var viewModel = {
filename: ko.observable(""),
url: ko.observable(),
spFileBinary:ko.observable(),
//Write your CLICK EVENTS
};
Hope This Helps :)