0



I am trying to bind form-data along with image(s) from HTML page to Angular Controller, then append form-data with image data, and finally POST data to an API.

So I searched, and got to know that, sadly AngularJs doesn't have any directive for image files.
So the ultimate solution I got is to create a custom directive, append form-data with image(s), and then POST that data to server.

What I tried:

HTML

<form role="form" enctype="multipart/form-data" name="myForm">
<input type="text"  ng-model="UserName" required="required">
<input type="text"  ng-model="FirstName" required="required">
<input type="file"  ng-model="Image" required="required">
<button type="submit" ng-click="product()">save</button>
</form>


Custom Directive :

myApp.directive('fileModel', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;

            element.bind('change', function(){
                scope.$apply(function(){
                    modelSetter(scope, element[0].files[0]);
                });
            });
        }
    };
}]);


POST Method :

scope.product = function() {
     var pro = $scope.pro;
     console.log('Form Data : ' + pro);
    var fd = new FormData();
    angular.forEach($scope.Image, function(file) {
        fd.append('file', file);
    });
    fd.append('pro', JSON.stringify($scope.product));
    $http.post('/products/createProduct', fd, {
            transformRequest: angular.identity,
            headers: {
                'Content-type': undefined
            }
        })
        .then(function(data) {
            $scope.ListProducts = data;
            console.log($scope.ListProducts );
        });

}


But the problem is, nothing is binding to the controller, and every-time my object is empty.
I even tried logging data to console, but got nothing inside data.
I don't know what I am doing wrong.
Please help..


Update

I am able to bind data, but while posting image-path along with other form-data I am getting all null.

angular.js:14642 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"POST","transfor‌​mRequest":[null],"tr‌​ansformResponse":[nu‌​ll],"jsonpCallbackPa‌​ram":"callback","url‌​":"/products/createP‌​roduct","data":{"pro‌​ductStock":[{"price"‌​:"","color":""}],"pr‌​oductThumbnail":{"0"‌​:{}}},"headers":{"Ac‌​cept":"application/j‌​son, text/plain, /","Content-Type":"application/json;charset=utf-8"}},"status‌​Text":""} error

georgeawg
  • 48,608
  • 13
  • 72
  • 95
mayank bisht
  • 618
  • 3
  • 14
  • 43
  • Keep in mind that uploading images with the [FormData API](https://developer.mozilla.org/en-US/docs/Web/API/FormData) is not efficient as the [base64 encoding](https://en.wikipedia.org/wiki/Base64) adds a 33% extra overhead. Consider uploading the file directly and using [url parameters](https://en.wikipedia.org/wiki/Query_string) for additional data. – georgeawg Aug 09 '17 at 21:24
  • @georgeawg: How can I do that? – mayank bisht Aug 10 '17 at 16:19
  • Status of -1 usually means a [CORS problem](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS). The browser has blocked the XHR because it violates [Same Origin Policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy). – georgeawg Aug 10 '17 at 17:36
  • Possible duplicate of [AngularJS No 'Access-Control-Allow-Origin' header](https://stackoverflow.com/questions/36734865/angularjs-no-access-control-allow-origin-header), Possible duplicate of [How to enable CORS in AngularJs](https://stackoverflow.com/questions/23823010/how-to-enable-cors-in-angularjs), Possible duplicate of [Angular HTTP: Status -1 and CORS](https://stackoverflow.com/a/42880660/5535245), etc. – georgeawg 5 hours ago – georgeawg Aug 10 '17 at 17:37

2 Answers2

0

The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:

Working Demo of "files-input" Directive that Works with ng-model

angular.module("app",[]);

angular.module("app").directive("filesInput", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function(e) {
        var files = elem[0].files;
        ngModel.$setViewValue(files);
      })
    }
  }
});
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app">
    <h1>AngularJS Input `type=file` Demo</h1>
    
    <input type="file" files-input ng-model="fileArray" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileArray">
      {{file.name}}
    </div>
  </body>

Thanks for the answer. I tried your code, and getting:

angular.js:14642 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"POST","transfor‌​mRequest":[null],"tr‌​ansformResponse":[nu‌​ll],"jsonpCallbackPa‌​ram":"callback","url‌​":"/products/createP‌​roduct","data":{"pro‌​ductStock":[{"price"‌​:"","color":""}],"pr‌​oductThumbnail":{"0"‌​:{}}},"headers":{"Ac‌​cept":"application/j‌​son, text/plain, /","Content-Type":"application/json;charset=utf-8"}},"status‌​Text":""} error

In my experience, the most common cause of status of a -1, is that the browser blocked the response because of a violation of Same Origin Policy.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and Fetch follow the same-origin policy. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain. To improve web applications, developers asked browser vendors to allow cross-domain requests.

The Cross-Origin Resource Sharing (CORS) mechanism gives web servers cross-domain access controls, which enable secure cross-domain data transfers. Modern browsers use CORS in an API container - such as XMLHttpRequest or Fetch - to mitigate risks of cross-origin HTTP requests.

See Use CORS to allow cross-origin access.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Thanks for the answer.I tried your code, and getting **angular.js:14642 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"/products/createProduct","data":{"productStock":[{"price":"","color":""}],"productThumbnail":{"0":{}}},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8"}},"statusText":""}** error – mayank bisht Aug 10 '17 at 17:10
  • Oh okay.If I am using `` then only I am getting above error.But if I am using ``, then there is no error,but that image name is not getting stored in database. – mayank bisht Aug 10 '17 at 18:35
  • I am getting this value in network-tab:`productThumbnail: {name: {0: {}}`,as you can see there is no image name. – mayank bisht Aug 10 '17 at 18:55
0

I made improve to your code. Basically you was using ng-model, instead of file-model like your directive says, also fd.append File no need iteraction if only have one file. Check the code and the plnkr.

CONTROLLER

$scope.product = function() {
     var pro = $scope.pro;
     var fd = new FormData();

    fd.append('file', $scope.form.Image);
    fd.append('pro', JSON.stringify($scope.form));
    $http.post('/products/createProduct', fd, {
            transformRequest: angular.identity,
            headers: {
                'Content-type': undefined
            }
        })
        .then(function(data) {
            $scope.ListProducts = data;
            console.log($scope.ListProducts );
        });
  };

HTML

<form role="form" enctype="multipart/form-data" name="myForm">
    <input type="text"  ng-model="form.UserName" required="required">
    <input type="text"  ng-model="form.FirstName" required="required">
    <input type="file" file-model="form.Image" required="required">
    <button type="submit" ng-click="product()">save</button>
</form>

{{form.Image.name}}

PLNKR EXAMPLE

**UPDATE **

in the network could see this. when sending data. enter image description here

Jesus Carrasco
  • 1,355
  • 1
  • 11
  • 15