Join the Stack Overflow Community
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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?

share|improve this question

This question has an open bounty worth +50 reputation from marlar ending in 8 hours.

The current answers do not contain enough detail.

The workaround suggested by Akinwale works but I need to understand why it does not without it. My setup is the same as the OP.

    
try initializing my file as the first line of your controller : $scope.myFile = {}; it is mostly the dot problem – entre Nov 24 '14 at 6:02
1  
I've made plunkr of the code you provided and it works fine: plnkr.co/edit/o9D2Q6Tzkesm5MTyqXFE?p=preview – EvAlex Nov 24 '14 at 6:09
1  
Experienced this issue today. Passing 'myFile' into the uploadDocs() function like this uploadDocs(myfile), seemed to do it – Akinwale Aug 21 at 15:29
    
the solution by @akinwale worked for me – Grinish Aug 31 at 18:56
    
I have the exact same problem with the same jsfiddle which for some reason doesn't work in my code but works fine in the fiddle. @Akinwale's solution works for me, but after having struggled for three hours, I would very much like to know WHY it doesn't work! This workaround is fine, but understanding the problem is important to me. – marlar Oct 3 at 17:50

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);
};
share|improve this answer
    
Same problem when you use ng-annotate, modelSetter does not work for me unless I use a service to share the variable. – warl0ck Jul 4 at 3:22

I have seen that tutorial but opted for using this library witch makes file uploading seamless: ng-file-upload

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.