Part 8 - How to upload files with AngularJS and ASP.NET MVC application.



Introduction

In the previous article of this series AngularJS With ASP.NET MVC I have explained how to retrieve and display master details tabular data with AngularJS and ASP.NET MVC. Today I will show you Part 8 - How to upload files with AngularJS and ASP.NET MVC application.
The file input type does not support 2 way binding, so we need to find an own solution for file uploads with AngularJS. Here In this example, I would like to how to upload files with AngularJS and ASP.NET MVC application.

Steps :

Step-1: Create table(s) into the database.

Open Database > Right Click on Table > Add New Table > Add Columns > Save > Enter table name > Ok.
In this example, I have used two tables as below

Step-2: Update Entity Data Model.

Go to Solution Explorer > Open your Entity Data Model (here "MyModel.edmx") > Right Click On Blank area for Get Context Menu > Update Model From Database... > A popup window will come (Entity Data Model Wizard) > Select Tables > Finish.



Step-3: Add a folder for Save uploaded files.

Go to Solution Explorer > Right Click on the project > Add > New Folder > Enter Folder Name
Here I have named the folder "UploadedFiles".

Step-4: Add new action into your controller (here in the Data Controller) for upload File and Save Data to the Database.

Here I have added "SaveFiles" Action into "DataController". Please write this following code

[HttpPost]
public JsonResult SaveFiles(string description)
{
    string Message, fileName, actualFileName;
    Message = fileName = actualFileName = string.Empty;
    bool flag = false;
    if (Request.Files != null)
    {
        var file = Request.Files[0];
        actualFileName = file.FileName;
        fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
        int size = file.ContentLength;

        try
        {
            file.SaveAs(Path.Combine(Server.MapPath("~/UploadedFiles"), fileName));

            UploadedFile f = new UploadedFile
            {
                FileName = actualFileName,
                FilePath = fileName,
                Description = description,
                FileSize = size
            };
            using (MyDatabaseEntities dc = new MyDatabaseEntities())
            {
                dc.UploadedFiles.Add(f);
                dc.SaveChanges();
                Message = "File uploaded successfully";
                flag = true;
            }
        }
        catch (Exception)
        {
            Message = "File upload failed! Please try again";
        }

    }
    return new JsonResult { Data = new { Message = Message, Status = flag } };
}

Step-5: Add a new js File for add a new AngularJS controller and a Factory

Go to Solution Explorer > Right Click on folder (where you want to saved your AngularJS controller files, here I have created a folder named "AngularController"  under Scripts Folder) > Add > Select Javascript file > Enter name > Add.

Write following code in this file.

angular.module('MyApp') // extending angular module from first part
.controller('Part8Controller', function ($scope, FileUploadService) {
    // Variables
    $scope.Message = "";
    $scope.FileInvalidMessage = "";
    $scope.SelectedFileForUpload = null;
    $scope.FileDescription = "";
    $scope.IsFormSubmitted = false;
    $scope.IsFileValid = false;
    $scope.IsFormValid = false;

    //Form Validation
    $scope.$watch("f1.$valid", function (isValid) {
        $scope.IsFormValid = isValid;
    });


    // THIS IS REQUIRED AS File Control is not supported 2 way binding features of Angular
    // ------------------------------------------------------------------------------------
    //File Validation
    $scope.ChechFileValid = function (file) {
        var isValid = false;
        if ($scope.SelectedFileForUpload != null) {
            if ((file.type == 'image/png' || file.type == 'image/jpeg' || file.type == 'image/gif') && file.size <= (512 * 1024)) {
                $scope.FileInvalidMessage = "";
                isValid = true;
            }
            else {
                $scope.FileInvalidMessage = "Selected file is Invalid. (only file type png, jpeg and gif and 512 kb size allowed)";
            }
        }
        else {
            $scope.FileInvalidMessage = "Image required!";
        }
        $scope.IsFileValid = isValid;
    };
    
    //File Select event 
    $scope.selectFileforUpload = function (file) {
        $scope.SelectedFileForUpload = file[0];
    }
    //----------------------------------------------------------------------------------------

    //Save File
    $scope.SaveFile = function () {
        $scope.IsFormSubmitted = true;
        $scope.Message = "";
        $scope.ChechFileValid($scope.SelectedFileForUpload);
        if ($scope.IsFormValid && $scope.IsFileValid) {
            FileUploadService.UploadFile($scope.SelectedFileForUpload, $scope.FileDescription).then(function (d) {
                alert(d.Message);
                ClearForm();
            }, function (e) {
                alert(e);
            });
        }
        else {
            $scope.Message = "All the fields are required.";
        }
    };
    //Clear form 
    function ClearForm() {
        $scope.FileDescription = "";
        //as 2 way binding not support for File input Type so we have to clear in this way
        //you can select based on your requirement
        angular.forEach(angular.element("input[type='file']"), function (inputElem) {
            angular.element(inputElem).val(null);
        });

        $scope.f1.$setPristine();
        $scope.IsFormSubmitted = false;
    }

})
.factory('FileUploadService', function ($http, $q) { // explained abour controller and service in part 2

    var fac = {};
    fac.UploadFile = function (file, description) {
        var formData = new FormData();
        formData.append("file", file);
        //We can send more data to server using append         
        formData.append("description", description);

        var defer = $q.defer();
        $http.post("/Data/SaveFiles", formData,
            {
                withCredentials: true,
                headers: { 'Content-Type': undefined },
                transformRequest: angular.identity
            })
        .success(function (d) {
            defer.resolve(d);
        })
        .error(function () {
            defer.reject("File Upload Failed!");
        });

        return defer.promise;

    }
    return fac;

});

Here I have created an angular controller named "Part8Controller" and a Factory named "FileUploadService" with $http injected service. I have explained a little about AngularJS controller here , about Factory here and about $http here.

Step-6: Add new action into your controller (here in the HomeController) for Get the view for upload file & save Data.

Here I have added "Part8" Action into "Home" Controller. Please write this following code

public ActionResult Part8() // Upload File with Data
{
    return View();
}

Step-7: Add view for the Action & design.

Right Click on Action Method (here right click on Part8 action) > Add View... > Enter View Name > Select View Engine (Razor) > Add.
Complete View
@{
    ViewBag.Title = "Part8";
}

<h2>Part8 - Upload file using Angular JS</h2>
<div ng-controller="Part8Controller">
    <form novalidate name="f1" ng-submit="SaveFile()">
        <div style="color: red">{{Message}}</div>
        <table>
            <tr>
                <td>Select File : </td>
                <td>
                    <input type="file" name="file" accept="image/*" onchange="angular.element(this).scope().selectFileforUpload(this.files)" required />
                    <span class="error" ng-show="(f1.file.$dirty || IsFormSubmitted) && f1.file.$error.required">Image required!</span>
                    <span class="error">{{FileInvalidMessage}}</span>
                </td>
            </tr>
            <tr>
                <td>Description : </td>
                <td>
                    <input type="text" name="uFileDescription" ng-model="FileDescription" class="{{(IsFormSubmitted?'ng-dirty' + (f1.uFileDescription.$invalid?' ng-invalid':''):'')}}" autofocus />                   
                </td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <input type="submit" value="Upload File" />
                </td>
            </tr>
        </table>

    </form>
</div>

@section Scripts{
    <script src="~/Scripts/AngularController/Part8Controller.js"></script>
}

Step-8: Run Application.


Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.