1

I am using a JavaScript /AngularJS code excerpt from an article I found online. I made a couple of tweaks to it, because the original post would not work on IE 11, but other than that I am using it as I found it. This piece of code, allows you to upload and read an Excel file to a jQuery data table.

There is one requirement that I am missing and would like to ask for help, if possible. that requirement is to only allow Excel files to be uploaded, an no other type of file should be "visible" to the user.

Here is the code I am using:

AngularJS controller:

var app = angular.module('MyApp', []);
app.controller('MyController', ['$scope', '$http', function ($scope, $http) {

    $scope.SelectedFileForUpload = null;

    $scope.UploadFile = function (files) {
        $scope.$apply(function () {   
            $scope.Message = "";
            $scope.SelectedFileForUpload = files[0];
        })
    }

    //Parse Excel Data   
    $scope.ParseExcelDataAndSave = function () {

        var file = $scope.SelectedFileForUpload;

        if (file) {

            var reader = new FileReader();

            reader.onload = function (e) {

                var filename = file.name;
                // pre-process data
                var binary = "";
                var bytes = new Uint8Array(e.target.result);
                var length = bytes.byteLength;

                for (var i = 0; i < length; i++) {
                    binary += String.fromCharCode(bytes[i]);
                }

                // call 'xlsx' to read the file
                var data = e.target.result;
                var workbook = XLSX.read(binary, { type: 'binary', cellDates: true, cellStyles: true });
                var sheetName = workbook.SheetNames[0];
                var excelData = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);

                if (excelData.length > 0) {
                    //Save data   
                    $scope.SaveData(excelData);
                }
                else {
                    $scope.Message = "No data found";
                }            };



            }
            reader.onerror = function (ex) {
                console.log(ex);
            }

            reader.readAsArrayBuffer(file);
        }

html view:

<body ng-app="MyApp">
    <div class="container py-4" ng-controller="MyController">
        <div class="card">
            <div class="card-header bg-primary text-white">
                <h5>Common Council List</h5>
            </div>
            <div class="card-body">

                @* Upload Button *@
                <button style="margin-bottom:10px;" type="button" class="btn btn-primary rounded-0" data-toggle="modal" data-target="#myModal">
                    <i class="fa fa-file-excel-o"></i> Upload Excel File
                </button>

                @* Modal Window *@
                <div class="modal" id="myModal">
                    <div class="modal-dialog">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h4 class="modal-title">Upload Common Council Data</h4>
                                <button type="button" class="close" data-dismiss="modal">×</button>
                            </div>
                            <div class="modal-body">
                                <div class="col-md-12">
                                    <div class="input-group">
                                        <div class="custom-file">
                                            <input type="file" name="file" class="custom-file-input" onchange="angular.element(this).scope().UploadFile(this.files)" />
                                            <label class="custom-file-label" for="inputGroupFile04">Choose file</label>
                                        </div>
                                        <div class="input-group-append">
                                            <button class="btn btn-outline-secondary" type="button" ng-disabled="!SelectedFileForUpload" ng-click="ParseExcelDataAndSave()"><i class="fa fa-upload"></i> Upload</button>
                                        </div>
                                    </div>
                                    <span class="text-success">
                                        {{Message}}
                                    </span>
                                </div>
                            </div>
                            <div class="modal-footer">
                                <button type="button" class="btn btn-danger rounded-0" data-dismiss="modal" ng-click="clearText()">Close</button>
                            </div>
                        </div>
                    </div>
                </div>



                @* Main Table *@
                <table id="dataTable" class="table table-bordered table-striped" ;>
                    <thead>
                        <tr>
                            <th style="width: 90px;">Meeting ID</th>
                            <th style="width: 105px;">Agenda Item</th>
                            <th style="width: 85px;">Legistar ID</th>
                            <th>Title</th>
                        </tr>
                    </thead>
                </table>


            </div>
        </div>
    </div>
</body>

Any help on this would be greatly appreciate it.

Thank you, Erasmo

Update

html mark-up

@* Modal Window *@
<div class="modal" id="myModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">Upload Common Council Data</h4>
                <button type="button" class="close" data-dismiss="modal">×</button>
            </div>
            <div class="modal-body">
                <div class="col-md-12">
                    <div class="input-group">
                        <div class="custom-file">
                            <input type="file" name="file" class="custom-file-input" onchange="angular.element(this).scope().UploadFile(this.files)" />
                            <label class="custom-file-label" for="inputGroupFile04">Choose file</label>
                        </div>
                        <div class="input-group-append">
                            <button class="btn btn-outline-secondary" type="button" ng-disabled="!SelectedFileForUpload" ng-click="ParseExcelDataAndSave()" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" />><i class="fa fa-upload"></i> Upload</button>
                        </div>
                    </div>
                    <span class="text-success">
                        {{Message}}
                    </span>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-danger rounded-0" data-dismiss="modal" ng-click="clearText()">Close</button>
            </div>
        </div>
    </div>
</div>

screen shot - upload file windows

2
  • What do you mean by "Excel files?" Do you mean files that have a .xlsx extension? How about older Excel extensions like .xls? How about .csv? How about Excel files with non-standard extensions? If it's as simple as limiting the filename to several known extensions, you can just do that at the HTML level with the pattern attribute on your <file> tag. Commented May 9, 2020 at 1:31
  • 1
    I can't see the accept attribute on your input in your updated question. Actually you should apply it to your input not your button Commented May 9, 2020 at 3:15

3 Answers 3

8

You can simply achieve this by adding accept attribute to your input like this:

<input type="file" accept=".csv" />

But if you want to be much more clear and accept all version of excel you should use this one instead:

<input type="file" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" />

For Excel Files 97-2003 (.xls), use:

application/vnd.ms-excel

For Excel Files 2007+ (.xlsx), use:

application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

Also, there is the same question in SO that you can find here.

Sign up to request clarification or add additional context in comments.

6 Comments

I tried this, but when I click the file upload button, I can still see all types of files, not just the aforementioned ones.
@erasmocarlos Check the live demo here. If you stick with the first input you will only see the .csv extension files.
@erasmocarlos You have an input like this: <input type="file" name="file" class="custom-file-input" onchange="angular.element(this).scope().UploadFile(this.files)" /> so you should apply the accept attribute to this one not to your button element. It won't work on buttons. Just try it and see the results.
@erasmocarlos Keep in mind, the button is for illustration only, the main work is on input with type file so that is the element who work for uploading here. You can read this for more information.
Totally my fault. I was adding the accept to the wrong element. My apologies. It works now. Thank you for your help, and patience explaining.
|
5
<input type="file" accept=".xlsx, .xls, .csv"/>

1 Comment

I tried this, but when I click the file upload button, I can still see all types of files, not just the aforementioned ones.
2

If you want something safe, check the magic numbers in the first n bytes of your file.

read Magic Numbers

something like this:

const isXlsFile = (chunk) => {
    const types = [
        {
            ext: 'xls',
            mime: 'application/vnd.ms-excel',
            // magic numbers
            bytes: new Uint8Array([0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00])
        },
        {
            ext: 'xlsx',
            mime: 'application/vnd.ms-excel',
            bytes: new Uint8Array([0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00])
        }
    ]

    for (const type of types) {
        if (chunk.indexOf(type.bytes) === 0) return type;
    }

    return false;
};

this is just to check, then if it matches your type you proceed to save the file

4 Comments

Nice idea, but that website doesn't list the magic numbers for Excel files.
@kmoser sorry, I already fixed the link
Hello @maxi, thank you it does look like a best way to do it, but I am unsure how to implement it within my code. Do you have a JavaScript code example? Thank you.
@erasmocarlos I edited the answer, see if it works for you

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.