AngularJS Multiple File Upload example using Web API

I have previously written couple of articles on file upload, especially multiple file upload in Asp.Net , along with other technologies such as Web API, HTML5 and JQuery etc. Now, in this article I am going to share with you a simple example on how to upload multiple files in AngularJS and Asp.Net Web API.

Every new version of AngularJS looks promising and it’s opening new opportunities for frontend developers. If you are working on Single Page Applications using Angular, then I am sure you will find this article and its example, very useful.

Related: File Upload Using HTML5, JQuery Ajax and Asp.Net Web API

Web API controller

The Web API controller, which I am going to use in this example, has the procedure for uploading the files at the server side. I have used this procedure many times in other articles. Therefore, I have now dedicated a separate post explaining the File Upload procedures in the API. This will spare me from writing the codes multiple times. Its written is C# and Vb.Net.

I am using XMLHttpRequest methods, in this example, to make calls to my API. Therefore, please click the below link and check the Web API controller.

The Web API Controller with the File Upload Procedure

Once you have created the API, it’s time to create the web page, using few AngularJS directives.

AngularJS View

<!DOCTYPE html>
<html>
<head>
  <title>File Upload Example in AngularJS</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
</head>

<body ng-app="fupApp">

    <div ng-controller="fupController">
        <input type="file" id="file" name="file" multiple
            onchange="angular.element(this).scope().getFileDetails(this)" />

        <input type="button" ng-click="uploadFiles()" value="Upload" />

        <!--ADD A PROGRESS BAR ELEMENT.-->
        <p><progress id="pro" value="0"></progress></p>
    </div>

</body>

In the markup section, I have three elements (2 input and 1 progress) packed inside a DIV element with ng-controller directive , defining the application controller. The <input> type file, is an HTML5 input type that will allow us to select multiple files at a time.

The elements onchange event will call the getFileDetails() function in the $scope using angular.element() method.

The angular.element() method is an interface between JQuery and AngularJS. Angular says, “use this method if you are not using JQuery in your application”. Therefore, when you select files, the angular.element calls the function defined in the scope.

Ref: Learn more about angular.element

The Controller and the Scope

<script>
    var myApp = angular.module('fupApp', []);

    myApp.controller('fupController', function ($scope) {

        // GET THE FILE INFORMATION.
        $scope.getFileDetails = function (e) {

            $scope.files = [];
            $scope.$apply(function () {

                // STORE THE FILE OBJECT IN AN ARRAY.
                for (var i = 0; i < e.files.length; i++) {
                    $scope.files.push(e.files[i])
                }

            });
        };

        // NOW UPLOAD THE FILES.
        $scope.uploadFiles = function () {

            //FILL FormData WITH FILE DETAILS.
            var data = new FormData();

            for (var i in $scope.files) {
                data.append("uploadedFile", $scope.files[i]);
            }

            // ADD LISTENERS.
            var objXhr = new XMLHttpRequest();
            objXhr.addEventListener("progress", updateProgress, false);
            objXhr.addEventListener("load", transferComplete, false);

            // SEND FILE DETAILS TO THE API.
            objXhr.open("POST", "/api/fileupload/");
            objXhr.send(data);
        }

        // UPDATE PROGRESS BAR.
        function updateProgress(e) {
            if (e.lengthComputable) {
                document.getElementById('pro').setAttribute('value', e.loaded);
                document.getElementById('pro').setAttribute('max', e.total);
            }
        }

        // CONFIRMATION.
        function transferComplete(e) {
            alert("Files uploaded successfully.");
        }
    });
</script>
</html>

Related: AngularJS File Upload using $http post and FormData

-----------------

Browser Support:
Chrome 39.0 - Yes | FireFox 34.0 - Yes | Internet Explorer 10 - Yes | Safari 5.1.7 - No

Note: Safari (v 5.1.7) cannot upload multiple files using XMLHttpRequest(). It will upload just one file at a time. This version does not support HTML5 <progress> element either. Therefore, if you are using Safari then I suggest you download Safari 6 or above (if possible) to make this example work.

-----------------

Function getFileDetails() inside the controller, takes a single parameter. This function is called when, you select files using the <input> file type, from the application view. The parameter has the elements information, such as, file type, number of files, names etc. Later, we will store each file’s information in an array.

The second method uploadFiles() is called when the user clicks the upload button.

$scope.uploadFiles = function ()

To upload the files, first I am using FormData() object to collect the file details from the array $scope.files[]. Once I have extracted the details, I’ll make a call to the Web API for upload. To do this I am using XMLHttpRequest. This is one of simplest method to make HTTP requests, using both GET and POST. Here, however I have to make a POST request, since I am sending file to the server to upload.

Before sending the data for processing, I have added two listeners, one for the progress of the file upload and the other a confirmation when it’s done.

objXhr.addEventListener("progress", updateProgress, false); //FOR PROGRESS.
objXhr.addEventListener("load", transferComplete, false); //FOR CONFIRMATION.

To show the progress, I have added an HTML5 <progress> element in the markup section. In the controller, I have declared a function that will update the progress for every byte it transfers.

The first listener (for progress) calls the updateProgress() function and receives values in bytes. I am assigning the values to <progress> elements two attributes, that is, value and max.

function updateProgress(e) {
    if (e.lengthComputable) {
        document.getElementById('pro').setAttribute('value', e.loaded);
        document.getElementById('pro').setAttribute('max', e.total);
    }
}

That’s it. Hope you find article and its example useful. If you have any queries, please leave a message below.

Related Posts:

Like this Article? Subscribe now, and get all the latest articles and tips, right in your inbox.

Enter your email id

Delivered by FeedBurner
Tweet this article Facebook Google+
comments powered by Disqus

Join our Google Plus Community and be a part of a discussion!