1

I've found this question and changed it a little and it seems to work fine as long as I'm using it outside of the ng-repeat.

But I can't get it to work for some reason inside my repeat, image.src is never updated. I guess this is more an issue of the scope than with the actual preview function. I can see that the console.log(attr.imageData); in line 13 of the plunk shows me a string image in the console. This should be the object from the loop I think.

So how can I get the preview image after I've selected a file?

Plunker link.

HTML:

<div ng-repeat="image in data.CmsPageImages">
    <a href="" ng-click="removeImage($index)" class="pull-right">
        <i class="fa fa-times"></i>
    </a>
    <input
        image-callback="test1"
        type="file"
        wa-file-select
        ng-model="image.file">
    <input
        type="text"
        required
        placeholder="Caption and copyright"
        ng-model="image.caption">
    <img ng-if="image.src" ng-src="image.src" style="width: 120px; height: auto;" />
</div>

The whole JS code:

angular.module('waFrontend', []);

angular.module('waFrontend').directive('waFileSelect', ['fileReader', function (fileReader) {
    return {
      require: '^ngModel',
      scope: {
        imageData: '='
      },
        link: function ($scope, el, attr) {
            el.bind('change', function(e) {
              var file = ((e.srcElement || e.target).files[0]);
          fileReader.readAsDataUrl(file, $scope).then(function (result) {
                attr.imageData.src = result;
            });
            })
        }
    }
}]);

angular.module('waFrontend').controller('SubmitNewsController', [
    '$scope', 'fileReader',
    function ($scope, fileReader) {

    $scope.data = {
        CmsPage: {
            title: ''
        },
        CmsPageImages: [
            {
                caption: '',
                file: null
            }
        ]
    };

    $scope.addImage = function() {
        $scope.data.CmsPageImages.push({
            caption: null,
            file: null
        });
    };

    $scope.removeImage = function(index) {
        $scope.data.CmsPageImages.splice(index, 1);
    };

    $scope.getFile = function(file, test) {
        $scope.progress = 0;
        $scope.file = file;
        fileReader.readAsDataUrl($scope.file, $scope).then(function (result) {
            $scope.imageSrc = result;
        });
    };

}]);

(function (module) {

    var fileReader = function ($q, $log) {

        var onLoad = function (reader, deferred, scope) {
            return function () {
                scope.$apply(function () {
                    deferred.resolve(reader.result);
                });
            };
        };

        var onError = function (reader, deferred, scope) {
            return function () {
                scope.$apply(function () {
                    deferred.reject(reader.result);
                });
            };
        };

        var onProgress = function (reader, scope) {
            return function (event) {
                scope.$broadcast("fileProgress",
                        {
                            total: event.total,
                            loaded: event.loaded
                        });
            };
        };

        var getReader = function (deferred, scope) {
            var reader = new FileReader();
            reader.onload = onLoad(reader, deferred, scope);
            reader.onerror = onError(reader, deferred, scope);
            reader.onprogress = onProgress(reader, scope);
            return reader;
        };

        var readAsDataURL = function (file, scope) {
            console.log(file);
            var deferred = $q.defer();

            var reader = getReader(deferred, scope);
            console.log(file);
            reader.readAsDataURL(file);

            return deferred.promise;
        };

        return {
            readAsDataUrl: readAsDataURL
        };
    };

    module.factory("fileReader", ["$q", "$log", fileReader]);

}(angular.module("waFrontend")));
Community
  • 1
  • 1
floriank
  • 25,546
  • 9
  • 42
  • 66

1 Answers1

1

console.log(attr.imageData) will show you only attr string which you're putting into it, to see exactly the image object you should use $scope.$eval(attr.imageData).

Also you forgot to add imageData param into your directive:

<input
    image-callback="test1"
    image-data="image"
    type="file"
    wa-file-select
    ng-model="image.file">

or delete it from the directive scope initialization, cause it may cause an error.

attr.imageData.src = result; - that's not going to work. Use $scope.imageData.src = result instead.

And it seems that you don't need ng-model="image.file" in your directive and require: '^ngModel' should be deleted as well, but keep it if you have further-going needs.

Anton Savchenko
  • 1,210
  • 1
  • 8
  • 11
  • Thank you, yes, I forgot the imageData param in the plunk. My main issue was the scope part. Could you please explain me how this works? As I understand it now, in link() attr contains the "raw" attributes and scope - already at this point - contains the parsed / evaluated attributes? I was not aware of that. – floriank May 13 '15 at 19:39
  • So attrs argument is an object which contains only tag element attributes with their values, more like you'd get if you tried to get them with jquery attr method. Attrs can be evaluated if you provide their names directly in scope object inside of directive initialization. And also this scope is local for directive, that means that you are able to access and modify any variable which is passed into scope. The evaluated attr param can only be read or assigned manually to another local variable in the directive scope cause it's persisted in parents scope (scopes are acting like prototypes in js) – Anton Savchenko May 13 '15 at 20:05