1

I have directive "notes" which is basically a notes widget that I can add on any page and just add a name and id to it to allow people adding notes to that item.

The users should be able to upload files to their notes using ng-file-upload as well now but I struggle to get the $scope.files populated by the ng-file-upload directive. I'm pretty sure it is as usual something stupid with the scope but I can't figure it out.

So any idea why $scope.files gets not populated when I select a file?

Plunker Link

Directive:

angular.module('app').directive('notes', [function () {
    return {
        restrict: 'E',
        templateUrl: 'notes.html',
        scope: {
            itemId: '@',
            itemModel: '@'
        },
        controller: ['$scope', 'Upload', function($scope, Upload) {
            $scope.files = [];
            $scope.notes = [
              {title: 'first title'},
              {title: 'second title'}
            ];

            $scope.$watch('files', function (files) {
                console.log(files);
                $scope.formUpload = false;
                if (files != null) {
                    for (var i = 0; i < files.length; i++) {
                        $scope.errorMsg = null;
                        (function (file) {
                            uploadUsingUpload(file);
                        })(files[i]);
                    }
                }
            });

            function uploadUsingUpload(file) {
                file.upload = Upload.upload({
                    url: '/api/v1/notes/upload_attachment',
                    method: 'POST',
                    //headers: {
                    //  'my-header': 'my-header-value'
                    //},
                    //fields: {username: $scope.username},
                    file: file,
                    fileFormDataName: 'file'
                });

                file.upload.then(function (response) {
                    $timeout(function () {
                        file.result = response.data;
                    });
                }, function (response) {
                    if (response.status > 0)
                        $scope.errorMsg = response.status + ': ' + response.data;
                });

                file.upload.progress(function (evt) {
                    // Math.min is to fix IE which reports 200% sometimes
                    file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
                });

                file.upload.xhr(function (xhr) {
                    // xhr.upload.addEventListener('abort', function(){console.log('abort complete')}, false);
                });
            }

        }]
    };
}]);

Template:

<ul>
  <li ng-repeat="note in notes">
    {{note.title}}
    <div ngf-select ng-model="files"><b>upload</b></div>
  </li>
</ul>
<pre style="border: 1px solid red;">{{files | json}}</pre>

3 Answers 3

2

I'm kind of late here but the reason why you're having a problem updating the $scope.files property is because a new scope is being created within your ng-repeat.

<ul>
    <li ng-repeat="note in notes">
        {{note.title}}
        <div ngf-select ng-model="$parent.files"><b>upload</b></div>
    </li>
</ul>
<pre style="border: 1px solid red;">{{files | json}}</pre>

For more information about how scoping works in angular check out https://github.com/angular/angular.js/wiki/Understanding-Scopes

Sign up to request clarification or add additional context in comments.

Comments

1

ng-file-upload sets the selected files object in the "files" model (or the attribute tied to ng-model) in the enclosing scope. In this case the enclosing scope is ng-repeat. If you set an attribute "files" in note object and set it as ng-model it should work.

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

<ul>
  <li ng-repeat="note in notes" >
    {{note.title}}
    <div ngf-select ng-model="note.files"><b>upload</b></div>
  </li>
</ul>

  // In directive
  $scope.notes = [{
    title: 'first title',
    files: []
  }, {
    title: 'second title',
    files: []
  }];

 //And you can watch the file model
  $scope.$watch(function($scope) {
    return $scope.notes.
    map(function(note) {
      return note.files;
    });
  }, function(files) {
      console.log('Files' + files);
  }, true)

2 Comments

This might work but then I'll have to use a deep watch or watch every single files property of each notes object? Doesn't sound like an ideal solution. Is there no way to pass the files instance from the notes directy through to the ng-repeat scope?
It is possible to pass one files instances. But the same instance is updated when file upload is done for another note. So you will have to upload file immediately as it is selected for one note or maintain a temp variable to keep track of all file changes (just thinking not sure how this work though). plnkr.co/edit/oVpgrSWQAcFdV26aVKv7?p=preview
0

I added the dynamic id with ngf-select and it's fine working for me.

<ul>
 <li ng-repeat="note in notes">
   {{note.title}}
   <div ngf-select id="file{{$index}}" ng-model="files"><b>upload</b></div>
  </li>
</ul>

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.