2

I have a img tag and an input file looking the like this:

<img ng-src="{{item.showImage || '//:0'}}" />
<input type="file" accept="image/*" onchange="angular.element(this).scope().getImage(this.files)"/>

on the controller I have the following function:

$scope.getImage = function(files){
 $scope.item.image = files[0];
 var reader = new FileReader();
 reader.onload = function(e){
 $scope.item.showImage = e.target.result;
 }
 reader.readAdDataURL($scope.item.image);
}

My purpose is to show the image selected by the user in the img tag using ng-src, this works only when I call $scope.$apply(), I wonder if there's a way to make it work without calling it?

Sara Fuerst
6,1389 gold badges49 silver badges95 bronze badges
asked Mar 29, 2015 at 12:03
2
  • no, see this issue: github.com/angular/angular.js/issues/1375 Commented Mar 29, 2015 at 12:13
  • @squiroid this is not a duplicate as i know how to catch the chnages, just wondering how to make the new file selected show in the ng-src Commented Mar 29, 2015 at 12:20

1 Answer 1

1

You can have a look at this plunker. You can use a directive for the image field that will watch for changes and will also return the image in a way that the template will be able to display it.

var UploadController = function ($scope, fileReader) {
 $scope.getFile = function () {
 fileReader.readAsDataUrl($scope.file, $scope)
 .then(function(result) {
 $scope.imageSrc = result;
 });
 };
};
app.directive("ngFileSelect",function(){
 return {
 link: function($scope,el){
 el.bind("change", function(e){
 $scope.file = (e.srcElement || e.target).files[0];
 $scope.getFile();
 })
 }
 }
});

Then you will also need that as a service:

(function (module) {
 var fileReader = function ($q, $log) {
 var onLoad = function(reader, deferred, scope) {
 return function () {
 scope.$apply(function () {
 deferred.resolve(reader.result);
 });
 };
 };
 var getReader = function(deferred, scope) {
 var reader = new FileReader();
 reader.onerror = onError(reader, deferred, scope);
 return reader;
 };
 var readAsDataURL = function (file, scope) {
 var deferred = $q.defer();
 var reader = getReader(deferred, scope); 
 reader.readAsDataURL(file);
 return deferred.promise;
 };
 return {
 readAsDataUrl: readAsDataURL 
 };
 };
 module.factory("fileReader",
 ["$q", "$log", fileReader]);
}(angular.module("plunker")));
answered Mar 29, 2015 at 12:28
Sign up to request clarification or add additional context in comments.

1 Comment

That's a great solution but still uses $scope.$apply, i was looking for something that doesn't require me to do that.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.