Upload multiple files in angular
Asked Answered
S

3

33

I've a situation where I've a form in which I've a row where I've two text fields entries and I've to upload a file for that row and this kind of rows can be 'N' and then there is a master files that can be entered for whole form while these are some part of the form and I've to submit all these files at once on clicking a save button.

I'm kind of stuck with ng-upload it needs an api call, and I really can't have more than one api call for this form. The sample html code is below :

<!DOCTYPE html>
<html>

<head>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>

<body>

  <form editable-form name="xyzForm" ng-submit="create(model)">
    <label>Tags: </label><input class="col-xs-12 col-md-12" ng-model="model.tags" type="text" name="Tags">
    <label>Notes: </label> <input class="col-xs-12 col-md-11" ng-model="model.notes" type="text" name="notes">
    <table class=" col-xs-3 col-md-11 table" border="1px solid red;">
      <thead>
        <tr>
          <th>Product</th>
          <th>Manufacturer</th>
          <th>Location</th>
          <th>Specification</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="itemRow in item.singleItem">
          <td><input type="text" class="xdTextBox" name="itemRow.name" ng-model="model.itemRow[$index].name" /></td>
          <td><input type="text" class="xdTextBox" name="itemRow.manufacturer" ng-model="model.itemRow[$index].manufacturer" /></td>
          <td><input type="text" class="xdTextBox" name="itemRow.location" ng-model="model.itemRow[$index].location" /></td>
          <td><i class="pull-left glyphicon glyphicon-upload"><input type="file" name="itemRow.doc" ng-model="model.itemRow[$index].doc" multiple=false></i></td>
          <td><i class="pull-left glyphicon glyphicon-remove"></i></td>
        </tr>

      </tbody>
      </span>
    </table>

    <label>Product Spec: </label><input type="file" ng-model="prefabdoc" multiple="true" ngf-maxsize="15000000" />
  </form>

</body>

</html>
Socket answered 14/7, 2015 at 10:49 Comment(6)
Is using https://github.com/danialfarid/ng-file-upload not an option?Eydie
I'm using the same thing already in my code, but confused how to implement this at once for multiple files and that too with different set of files at different places in the formSocket
This is also a good resource on youtube: youtube.com/watch?v=sm84cTdkd80Pascoe
@Bran Stark - I am trying to achieve exactly what you have mentioned above in your problem statement.I am new to Angular Js and I found accepted answer below somewhat close but still not clear how can I implement for the problem statement as you mentioned above.Can you please share code which you implemented,it would be really helpful..Thanks.Anticathexis
Did the accepted answer work for you @BranStark?Spanish
Yes, it worked for me @SpanishSocket
P
51

Here is file value binding directive example ..

http://plnkr.co/edit/B13t84j5IPzINMh1F862?p=preview

Js code is:

var app = angular.module('myApp', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.files = []; 
  $scope.upload=function(){
    alert($scope.files.length+" files selected ... Write your Upload Code"); 

  };
});


app.directive('ngFileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var model = $parse(attrs.ngFileModel);
            var isMultiple = attrs.multiple;
            var modelSetter = model.assign;
            element.bind('change', function () {
                var values = [];
                angular.forEach(element[0].files, function (item) {
                    var value = {
                       // File Name 
                        name: item.name,
                        //File Size 
                        size: item.size,
                        //File URL to view 
                        url: URL.createObjectURL(item),
                        // File Input Value 
                        _file: item
                    };
                    values.push(value);
                });
                scope.$apply(function () {
                    if (isMultiple) {
                        modelSetter(scope, values);
                    } else {
                        modelSetter(scope, values[0]);
                    }
                });
            });
        }
    };
}]);

Html Code is:

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link href="style.css" rel="stylesheet" />
    <script data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js" 
        data-require="[email protected]"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>
    <input type="file" ng-file-model="files" multiple />
    <button type="button" ng-click="upload()">Upload</button>

    <p ng-repeat="file in files">
      {{file.name}}
    </p>
  </body>

</html>
Psalmist answered 27/7, 2015 at 3:1 Comment(5)
how to limit the number of files uploadable, like maximum 5 files needs to be uploaded onceNorahnorbert
you can do it on $scope.upload method $scope.file.length>5 and dont forget this code is only explains how to bind angularjs and fileinput ... read about file uploading developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/… and replace with the alert code.. i hope this helps ..Psalmist
So, now the files are available in controller through the "values" array right? As values[i]. Why are you accessing it using "files" variable in your upload function?Wordsworth
outputs something like this in php [additionals] => [object File],[object File]Frazzle
the object of this directive supports browser base view before upload show file , name size validation etc. you can access raw file by value._filePsalmist
O
6

If you don't care about browsers less than IE 9. Then you can follow this post and construct a FormData object in your ng-submit event. This will create a form/multipart and might not be what your looking for but it does the trick.

Officialism answered 20/7, 2015 at 10:57 Comment(5)
Thank You for pointing out this post. I've two different type of form files here one or more for each product item and for whole product itself one or more files.But I like the way the multiform is implemented here.Socket
It should be possible to combine the two type of form files into one FormData object just before you issue the post request. Haven't tried it myself though :)!Officialism
yeah sounds good, I'm trying this right now, let me see if I can get all the file data onto server side.Socket
Im kind of stuck, I want to do the $http post in another method, while Im trying to populate file data into fd from the above link, and file data does not display. FormData is empty even after appending the fileSocket
I'm trying to do $http.post in a different method, I want to return this FormData there, but this comes empty? What am I doing wrong, filedatais not going into FormData here is the code pastebin.com/DM4LNWkFSocket
E
1

from saltuk's answer above there is a small change for the code to work

    var modelSetter = model.assign;
        element.bind('change', function () {
            var values = [];
            angular.forEach(element[0].files, function (item) {
                var value = {...
                }
            }
        }

the array var should be defined above before forEach function

    var modelSetter = model.assign;
    element.bind('change', function () {
        var values = [];
        angular.forEach(element[0].files, function (item) {
            var value = {...
            }
        }
    }
Epitomize answered 6/7, 2016 at 10:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.