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>

6
  • 2
    Is using https://github.com/danialfarid/ng-file-upload not an option? Commented Jul 20, 2015 at 11:11
  • 1
    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 form Commented Jul 20, 2015 at 11:13
  • This is also a good resource on youtube: youtube.com/watch?v=sm84cTdkd80 Commented Feb 2, 2017 at 11:24
  • @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. Commented Mar 7, 2017 at 5:59
  • Did the accepted answer work for you @BranStark? Commented Sep 13, 2018 at 23:24

3 Answers 3

51
+50

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>
Sign up to request clarification or add additional context in comments.

5 Comments

how to limit the number of files uploadable, like maximum 5 files needs to be uploaded once
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 ..
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?
outputs something like this in php [additionals] => [object File],[object File]
the object of this directive supports browser base view before upload show file , name size validation etc. you can access raw file by value._file
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.

5 Comments

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.
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 :)!
yeah sounds good, I'm trying this right now, let me see if I can get all the file data onto server side.
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 file
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/DM4LNWkF
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 = {...
            }
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.