简体   繁体   中英

js-xlsx in knockout - pass sheet data back to page/viewmodel

Using the js-xlsx package, I'm reading in an excel file (successfully) from the page, but I'm stuck trying to pass that data back up the chain so the page can get the use of it.

I've got a function written in the viewmodel that fires on change of the in input:

<input name="xlfile" id="xlf"  class="left" data-bind="event: { change: function () { handleXLSfile($element) } }" style="width: 200px;" type="file">

That runs a quick pre-check of the file, then calls the XLSX function like this:

        self.XLSdata = [];
        self.EnrollstoValidate = [];


        self.handleXLSfile = function (element) {
            self.validManifest(false);
            //var rABS = true;
            var rABS = typeof FileReader !== "undefined" && (FileReader.prototype || {}).readAsBinaryString;

            var files = element.files;
            var f = files[0];
            var fileNamePieces = f.name.split('.');
            if (fileNamePieces.length <= 0) {
                self.validManifest(false);
            }
            else {
                var extension = fileNamePieces[fileNamePieces.length - 1];
                if (extension == "xls" || extension == "xlsx") {

                    self.validManifest(true);

                    do_xlsfile(f);

                }
            }
        };

I have the relevant XLSX functions in their own js file, as I have three pages that will be retrieving similar files, and it makes more sense to have one function that all three that each calls, and passes back the data:

var global_wb;

X = XLSX;

var process_wb = (function () {
    var strOUT = "";

    var to_json = function to_json(workbook) {
        var result = {};
        workbook.SheetNames.forEach(function (sheetName) {
            var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName], { header: 1 });
            if (roa.length) result[sheetName] = roa;
        });
        return result;
    };

    return function process_wb(wb) {
        global_wb = wb;
        var output = "";
        output = to_json(wb);
        strOUT = output;
        if (typeof console !== 'undefined') console.log("output", new Date());
        return output;
    };
})();

var do_xlsfile = (function (f) {
    var rABS = typeof FileReader !== "undefined" && (FileReader.prototype || {}).readAsBinaryString;

    return function do_file(f) {
        var XLSoutput = "";
        var rABS = false;
        var reader = new FileReader();
        reader.onload = function (e) {
            if (typeof console !== 'undefined') console.log("onload", new Date());
            var data = e.target.result;
            data = new Uint8Array(data);
            XLSoutput = process_wb(X.read(data, { type: rABS ? 'binary' : 'array' }));
            //self.XLSdata = XLSoutput;
        };
        reader.readAsArrayBuffer(f);
    };
})();

As I walk through it, it seems that the contents of the reader.onload fires after the function is finished calling, so I can't get it to do a return, which I've tried.

I'm trying to figure out how/where I can pass the XLSoutput object back to the Knockout area so I can manipulate it, display it on the screen, etc.

It's likely a combination of being relatively new to Knockout, and not knowing enough about how the xlsx package works to know what I can fiddle with.

Of course, the js-xlsx package has samples for damn near every other language in creation save for Knockout.

I have a fix in place, but it seems clunky, and I'm not sure there isn't a better solution.

I've added a global variable I can access later

self.handleXLSfile = function (element) {
            self.validManifest(false);
            global_BulkPage = "one2M";

And in the reader.onload above, I've added a function that grabs the value and sends the data to the right viewmodel

  var Send2KO = function (XLSoutput) {
        switch (global_BulkPage) {
            case "one2M":
                ad.views.bulk_one2m.viewModel.XLSdata = XLSoutput;
                break;
            case "m2M":
                ad.views.bulk_m2m.viewModel.XLSdata = XLSoutput;
                break;
            case "delete":
                ad.views.bulk_delete.viewModel.XLSdata = XLSoutput;
                break;
            default:
            //no action
        }
    }

So I have access to the data back at the Knockout level - now I just have to work out the right way to access it from there. But that's another question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM