Thursday 26 January 2017

Create a file upload control as directive with progress bar and abort options using angular js

In this post we are going to see how to create a file upload control with progress bar and abort options using angular js. we are going to use the existing module angular-file-upload.js , angular-file-upload-shim.js create by daniel , This needs to be add as reference to our project. Where angularFileUpload module is added as dependency module in root module.



    <script src="~/Scripts/angular.js" type="text/javascript"></script>
    <script src="~/Scripts/angular-route.js" type="text/javascript"></script>
    <script src="~/Scripts/angular-file-upload.js" type="text/javascript"></script>
    <script src="~/Scripts/angular-file-upload-shim.js"  type="text/javascript"></script>


First we have to create a Directive which will acts as Fileupload control. where the directive have options like showing progress bar and abort options.

progressWidth directive change the progress bar width while uploading

var rgapp = angular.module('rgapp', ['angularFileUpload']);

rgapp.directive('progressWidth', [function () {
    return {
        restrict:'A',
        scope: {
            progressWidth:'='
        },
        link: function (scope, elem, attr, cntrl) {           

            var width = (elem.prop('offsetWidth') * scope.progressWidth) / 100
            angular.element(elem.find('div')).css('width', width + 'px');

            scope.$watch(function () { return scope.progressWidth; }, 
             function (newval, oldval) {
                if (newval != oldval) {
                    var width = (elem.prop('offsetWidth') * scope.progressWidth) / 100;
                    angular.element(elem.find('div')).css('width', width + 'px');
                }
            });
        }
    }
}]);



rgapp.directive('fileuploadForm', ['$upload', function ($upload) {
    return {
        scope: {
            asyncurl: '@',          
            successCallback: '&',
            fileselectCallback:'&',
            errorCallback: '&',
            inputData:'='
        },
        restrict: 'E',
        templateUrl:'../App/templates/upload.html',
        link: function (scope, element, attr, cntrl) {

            scope.progressFiles = [];
            var uploadingFiles = [];
            var uploadFileHandlers = [];

            scope.uploadedFilesString = '';

            scope.uploading = function(){
                for (var i = 0; i < uploadingFiles.length; i++) {
                    var _file = uploadingFiles[i];
                    scope.progressFiles[i].isabort = false;
                    scope.progressFiles[i].isfinished = false;
                    (function (indx) {

                        scope.progressFiles[i].isprogress = true;

                        uploadFileHandlers[indx] = $upload.upload({
                            url: attr.asyncurl,
                            method: 'POST',
                            file: _file,
                            data: scope.inputData
                        })
                            .progress(function (prg) {
                                console.log("index " + indx);
                                scope.progressFiles[indx].progress = 
                                              Math.round((prg.loaded * 100) / prg.total);

                                if (scope.progressFiles[indx].progress==100)
                                    scope.progressFiles[indx].isfinished = true;
                                })

                            .success(function (data, status, headers, config) {

                                scope.progressFiles[indx].isprogress = false;
                                scope.progressFiles[indx].isfinished = true;

                                if (scope.successCallback)
                                    scope.successCallback({ data: data, status: status, 
                                        headers: headers, config: config });

                            })
                            .error(function (data, status, headers, config) {

                                scope.progressFiles[i].isabort = true;

                                if (scope.errorCallback)
                                scope.errorCallback({ data: data, status: status, headers: 
                                       headers, config: config });
                            });

                   })(i);

                }
                uploadingFiles = [];
                scope.uploadedFilesString = '';
            }

            scope.abort = function (indx) {
                if (uploadFileHandlers.length > indx) {
                    uploadFileHandlers[indx].abort();
                    scope.progressFiles[indx].isabort = true;  
                    scope.progressFiles[indx].isprogress = false;                
                }
            }

            scope.close = function (indx) {                                 
                scope.progressFiles[indx].isshow = false;               
            }

            scope.uploadedFiles = function (files) {

                uploadingFiles = files;
                scope.progressFiles = [];
                scope.uploadedFilesString = '';
                for (var i = 0; i < uploadingFiles.length; i++) {

                    scope.uploadedFilesString += uploadingFiles[i].name + ";";
                    scope.progressFiles[i] = {  
                           isshow:true,isprogress:false, index: i, isabort: false,
                           isfinished: false, extn: '',filecolor:''
                           filename: uploadingFiles[i].name, size: uploadingFiles[i].size, 
                           progress: 0, type: uploadingFiles[i].type };

                    scope.progressFiles[i].extn = scope.progressFiles[i].filename.substr(
                           scope.progressFiles[i].filename.lastIndexOf('.') + 1);
                    
     scope.progressFiles[i].filecolor = scope.getExtensionFile(scope.progressFiles[i].extn);

                }

                if (scope.fileselectCallback)
                    scope.fileselectCallback({ files: files });
            }
           

            scope.browseFiles = function () {
                document.getElementById('rgfile').click();               
            }
           

            scope.getExtensionFile = function (extn) {
                switch (extn) {
                    case "jpg":
                    case "png":
                    case "bmp":
                        return "#7b8c25";
                        break;
                    case "xls":
                    case "xlsx":
                    case "csv":
                        return "#468847";
                        break;
                    case "doc":
                    case "docx":
                        return "#428bca";
                        break;
                    case "ini":
                    case "jar":
                    case "zip":
                        return "#773472";
                        break;
                    case "exe":
                        return "#bce8f1";
                        break;
                    default:
                        return "red";
                }
            }
           
        }
    }
}]);




Template:
**************************
<div>
    <div class="" style="width:500px">
        <div class="form-inline" style="padding:20px">
            <label>Files :</label>
            <input type="text" ng-model="uploadedFilesString" class="form-control" />
            <button ng-click="browseFiles()" class="btn btn-sm">Browse</button>
            <button ng-click="uploading()" class="btn btn-sm btn-success">Upload</button>
        </div>
        <div class="form-group">
            <input  type="file" style="display:none" ng-file-select="uploadedFiles($files)" 
                    class="form-control" id="rgfile"
                    ng-model="user.file" multiple />
        </div>        
        <div>
            <div class="panel">
                <div ng-show="upfile.isshow" class="row container" style="padding:10px;" 
                     ng-repeat="upfile in progressFiles">                   
                    <div class="col-lg-2 col-md-2 col-sm-2">
                        <span style="color: {{upfile.filecolor}};font-size: 40px;
                           position: absolute;" class="glyphicon glyphicon-file"></span>
                        <span style="font-size: 12px;font-weight: 600;color: white;
                              position: absolute;margin-top:25px;
                              border-top-left-radius: 5px;width: 35px;
                              text-align:center">{{upfile.extn}}</span>
                    </div>
                    <div class="col-lg-5 col-md-5 col-sm-5">
                        <strong style="padding:5px;">File : {{upfile.filename}}</strong>
                        <div style="padding:5px;">Size : {{upfile.size}}</div>
                    </div>                   
                    <div class="col-lg-5 col-md-5 col-sm-5">
                        <div class="row container">
                            <div class="col-lg-10 col-md-9 col-sm-8">
                                <div style="border:1px solid green;border-radius:5px;
                                   margin-top:10px;background-color:lightgray" 
                                   progress-width="upfile.progress">
                                    <div ng-show="!upfile.isabort" 
                                         style="border:1px solid green;border-radius:5px;
                                         background-color:lawngreen;width:40px;"></div>
                                    <div ng-show="upfile.isabort" 
                                         style="border:1px solid red;border-radius:5px;
                                         background-color:lawngreen;width:40px;"></div>
                                </div> 
                                <div>
                                    <button ng-show="upfile.isprogress" 
                                        style="margin-top:5px;" 
                                        ng-click="abort(upfile.index)" 
                                        class="btn btn-danger btn-xs">Abort</button>
                                    
                                    <button ng-show="upfile.isfinished" 
                                        style="margin-top:5px;" 
                                        ng-click="close(upfile.index)" 
                                        class="btn btn-success btn-xs">Close</button>
                                    
                                   <button ng-show="upfile.isabort" 
                                        style="margin-top:5px;" 
                                        ng-click="close(upfile.index)" 
                                        class="btn btn-warning btn-xs">Close</button>
                                </div>
                                                          
                            </div>                           
                            <div class="col-lg-2 col-md-3 col-sm-4">
                              <span><strong>{{upfile.progress}}%</strong>
                              </span>                              
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



Controller 

rgapp.controller('blogcontroller', ['$scope','$upload',function ($scope,$upload) {

    $scope.Files = [];
    $scope.FilesData = [];
    $scope.filedata = { trackingid:'', description:''};

    $scope.success = function (data,status,headers,config) {
        console.log('config');
        console.log(config);
        $scope.FilesData.push(data);
    }

    $scope.error = function (data,status,headers,config) {
        console.log('error');
        console.log(config);
    }

    $scope.uploadfiles = function (files) {
        console.log(files);
    }

    $scope.uploadFile = function () {

        for (var i = 0; i < $scope.Files.length; i++) {

            var file = $scope.Files[i];

            $upload.upload({

            }).progress(function (evt) {

                }).success(function (evt) {

                })

        }

    }

    $scope.uploadedFiles = function (files) {
        $scope.Files = files;
    }

}]);



Html:
**************** 
<div ng-controller="blogcontroller">
    <div>
        <div style="margin-left:25px;">
            <fileupload-form asyncurl="~/api/Blog"
                             method="post"
                             input-data="filedata"
                             fileselect-callback="uploadfiles(files)"
                             success-callback="success(data,status,headers,config)"
                             error-callback="error(data,status,headers,config)">
            </fileupload-form>
        </div>
    </div>  
</div>



MVC Controller:
********************

        [CheckMimeMultiPart]
        public void Post()
        {
            try
            {
                var path = HttpContext.Current.Server.MapPath("~/files");
                var sprovide = new MultipartFormStreamProvider(path);
                await Request.Content.ReadAsMultipartAsync(sprovide);             
                 
            }catch(Exception ex)
            {
               
            }

        }


Output:
*********************






Once you click on the upload button, the files starts showing the progress bar with abort options like below, if you click abort then it will change the color of progress bar and shows the close button













From this post you can learn how to create a file upload control with progress bar and abort options using angular js