Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular File Upload directive not updating controller model

I am attempting to follow this [tutorial] but can't get it working.

My Angular controller is logging undefined for a model created in my directive. Here is a [JSFiddle] of it working created my author of tutorial.

The problem is the view can find $scope.myFile and but controller does not ($scope.myFile is undefined).

The view displays {{ myFile.name }} (as just example my-image.jpg). The myFile variable is a JS object containing data on selected file. This works fine. The directive seems to be assigning the model the value of selected file (and thus displays it correctly in view).

<input file-model="myFile" type="file"/ >
<div class="label label-info">
  {{ myFile.name }}
</div>
<button ng-click="uploadDocs()">Click</button>

Here is the directive I got from this [tutorial].

Since input type file can't use ng-model, this directive sets up the model to be associated with an file input, assigning to it every time the file fires change event.

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(){
              if (element[0].files.length > 1) {
                modelSetter(scope, element[0].files);
              }
              else {
                modelSetter(scope, element[0].files[0]);
              }
            });
          });
        }
      };
    }
  ]).

In the controller I just log $scope.myFile. This is called from the button in the HTML above. Ideally, I'd be uploading the files to server here, but I can't because $scope.myFile is undefined.

$scope.uploadDocs = function() {
  var file = $scope.myFile;
  console.log($scope.myFile);
};

Can someone tell me why the view would be recieving $scope.myFile but the controller logs undefined for $scope.myFile?

like image 750
GN. Avatar asked Nov 24 '14 05:11

GN.


2 Answers

I ran into the same problem when trying to access a directive's variable from the controller. In my case I could make myFile available to the controller, but I had to assign it to scope.$parent.$parent.myFile from within the directive. I didn't want to hard code in a depth of ancestry in order to access the variable, so I ended up using a service to share the variable between directive and controller:

.factory('fileService', function() {
    var files = [];
    return files;
})

My directive code changed to use the service instead of attrs.fileModel that was used in the tutorial:

.directive('fileModel', ['$parse', 'fileService', function ($parse, fileService) {
    return {
        restrict: 'A',
        link: function(scope, element) {
            element.bind('change', function(){
                scope.$apply(function(){
                    if (element[0].files != undefined) {
                        fileService.push(element[0].files[0]);
                        console.log('directive applying with file');
                    }
                });
            });
        }
    };
}])

Then, after injecting fileService into the controller I could access the file directly from fileService:

$scope.uploadDocs = function() {
    console.log(fileService);
};
like image 92
Glen Avatar answered Oct 05 '22 13:10

Glen


This issue is seen in couple of Angular versions, where file object can't be set the scope variable. As a work around make, pass the field to controller, use this file object to upload ( not from scope)

HTML Form

<form>
    <div class="form-group">
                    <label for="myFileField">Select a file: </label> 
                    <input type="file" file-model="myFile" /> <label>File Name:</label> 
                    <input type="text" ng-model="filename"></input>
                </div>
                <button ng-click="uploadFile(myFile)" class="btn btn-primary">Upload File</button>
            </form>

Controller

 $scope.uploadFile = function (file1) {
            var file = $scope.myFile;  // this is undefined 
            console.log("My file =" +file1); // you get this 
            // Make http call to upload the file or make service call         
 }

Hope this solves the problem

like image 27
Satheesh Cheveri Avatar answered Oct 05 '22 13:10

Satheesh Cheveri