Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout JS: Fileupload event

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);
                    }
                });
            }
        });
like image 972
lincx Avatar asked Oct 21 '22 06:10

lincx


1 Answers

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 :)

like image 78
praneeth4victory Avatar answered Oct 27 '22 09:10

praneeth4victory