File upload with AngularJS and XHR(2)

by andredgusmao

HTML

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.js"></script>
<div ng-controller="UploadCtrl">    
    <input type="file" multiple ng-model="files" file-change>
    <br><br>
    Selected: {{ files.length }}
</div>

JavaScript

// Module
// ------
var upload = angular.module('upload', []);


// Directive
// ---------
upload.directive('fileChange', function () {

    var linker = function ($scope, element, attributes) {
        // onChange, push the files to $scope.files.
        element.bind('change', function (event) {
            var files = event.target.files;
            $scope.$apply(function () {
                for (var i = 0, length = files.length; i < length; i++) {
                    $scope.files.push(files[i]);
                }
            });
        });
    };

    return {
        restrict: 'A',
        link: linker
    };

});


// Factory
// -------
upload.factory('uploadService', ['$rootScope', function ($rootScope) {

    return {
        send: function (file) {
            var data = new FormData(),
                xhr = new XMLHttpRequest();

            // When the request starts.
            xhr.onloadstart = function () {
                console.log('Factory: upload started: ', file.name);
                $rootScope.$emit('upload:loadstart', xhr);
            };

            // When the request has failed.
            xhr.onerror = function (e) {
                $rootScope.$emit('upload:error', e);
            };

            // Send to server, where we can then access it with $_FILES['file].
            data.append('file', file, file.name);
            xhr.open('POST', '/echo/json');
            xhr.send(data);
        }
    };

}]);


// Controller
// ----------
upload.controller('UploadCtrl', ['$scope', '$rootScope', 'uploadService', function ($scope, $rootScope, uploadService) {

    // 'files' is an array of JavaScript 'File' objects.
    $scope.files = [];

    $scope.$watch('files', function (newValue, oldValue) {
        // Only act when our property has changed.
        if (newValue != oldValue) {
            console.log('Controller: $scope.files changed. Start upload.');
            for (var i = 0, length = $scope.files.length; i < length; i++) {
     ...