2015-01-28 5 views
1

Моя цель состоит в том, чтобы взять массив URL-адресов изображений (полученных из API, их заголовки CORS установлены) и перебрать его, извлечь каждое изображение с помощью xhr, изменив его размер элемент холста, а затем сгенерировать еще один массив, чьи записи являются данными для измененных изображений. Моя проблема в том, что только последняя запись в массиве обрабатывается должным образом, а все остальное - пустым изображением. Я предполагаю, что $ q.deferred() перезаписывается на каждой итерации цикла, но я действительно не знаю, потому что я новичок в обещаниях и асинхронных действиях. Кроме того, я пишу это в AngularJS v1.25. Вы можете просмотреть мой код по адресу http://codepen.io/anon/pen/razwyZ?editors=101. Я также разместим его здесь:

var myApp = angular.module('myApp', []); 
 

 
//myApp.directive('myDirective', function() {}); 
 
//myApp.factory('myService', function() {}); 
 

 
myApp.controller('MyCtrl', ['$scope', '$q', 
 
    function($scope, $q) { 
 

 
    resizeImage = function(imgSrc) { 
 
     var deferred = $q.defer(); 
 
     // console.log(imgSrc); 
 
     // console.log("resizing image"); 
 
     image = new Image(); 
 
     image.src = imgSrc; 
 
     image.onload = function() { 
 
     var canvas = document.createElement("canvas"); 
 
     canvas.height = 300; 
 
     canvas.width = 300; 
 

 
     var ctx = canvas.getContext("2d"); 
 
     ctx.drawImage(image, 0, 0, 300, 300); 
 
     deferred.resolve(canvas.toDataURL("image/png")); 
 
     }; 
 

 
     return deferred.promise; 
 
    }; 
 

 
    fetchImage = function(src) { 
 
     var deferred = $q.defer(); 
 
     var xhr = new XMLHttpRequest(); 
 
     xhr.responseType = 'blob'; 
 

 
     xhr.onload = function() { 
 
     var url = URL.createObjectURL(xhr.response); 
 
     image = new Image(); 
 
     resizeImage(url) 
 
      .then(function(dataUri) { 
 
      deferred.resolve(dataUri); 
 
      }); 
 
     }; 
 

 
     xhr.open('get', src); 
 
     xhr.send(); 
 

 
     console.log(deferred.promise); 
 
     return deferred.promise; 
 
    }; 
 

 
    $scope.picUrls = ["https://res.cloudinary.com/mediocre/image/upload/v1415293060/od9rkw2xtdtfsfiblq6k.png", "https://res.cloudinary.com/mediocre/image/upload/v1415293108/pgnbdgx0aamspgcxzwmx.png", "https://res.cloudinary.com/mediocre/image/upload/v1415294024/z7ohumjr5vs87e1nn5fl.png", "https://res.cloudinary.com/mediocre/image/upload/v1422407613/mzuce3ooqpcewddq9iih.png"]; 
 
    $scope.picArray = []; 
 

 
    for (i = 0; i < $scope.picUrls.length; i++) { 
 
     console.log("executing loop") 
 
     $scope.picArray.push(fetchImage($scope.picUrls[i])); 
 
    } 
 

 
    $q.all($scope.picArray).then(function(imgArray) { 
 
     console.log("executing q.all statement"); 
 
     $scope.picArray = imgArray; 
 
     console.log($scope.picArray); 
 
    }); 
 

 
    } 
 
]);
<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
</head> 
 

 
<body> 
 
    <div ng-app="myApp" ng-controller="MyCtrl"> 
 
    <div ng-repeat="pic in picArray"> 
 
     <img src="pic"> 
 
    </div> 
 
    </div> 
 
</body> 
 

 
</html>

ответ

0

Вы на самом деле обещания с отложенным правильно. Я не знаю, почему вы использовали $q.defer() и xhr, когда вы могли только что использовать $http.get, который возвращает обещание уже.

У вас есть две небольшие проблемы, хотя:

1) вы должны использовать ng-src и не src, а выражение должно быть в фигурных скобках. Без ng-src, браузер будет пытаться скачать с местоположения "/{{pic}}".

2) у вас возникла ошибка с ng-repeat из-за массива с повторяющимися записями. Чтобы исправить, необходимо добавить track by (и в целом, чтобы лучше видеть ошибку, удалите .min из angular.min.js

<div ng-repeat="pic in picArray"> 
    <img ng-src="{{pic}}"> 
</div> 

EDIT:.

У вас есть еще несколько вопросов

1.) В вашем resizeImage и в fetchImage вы забыли объявить переменную image локально, и поскольку вы не использовали "use strict" (плохая идея прямо там), вы создали глобальный image переменная.

Изменить его:

var image = new Image(); 

2) Не используйте массив, хранящий обещает затем хранить изображения. Это создает неудачные HTTP-запросы для извлечения src изображения.

Используйте другие переменный:

$scope.pics = []; 

// then in `$q.all` 
$scope.pics = imgArray; 

и ng-repeat над этим:

<div ng-repeat="pic in pics track by $index"> 
    <img ng-src="{{pic}}"> 
</div> 

fork of your codepen

+0

Итак, я установил мои опечатки, как вы сказали, но [codepen] (HTTP : //codepen.io/anon/pen/pvrdaL? editors = 101) все еще имеет неожиданное поведение, о котором я говорил, - обрабатывается только последняя запись в массиве, а остальные - дубликаты пустых изображений. Также я не понимаю, почему мой оператор console.log в конце записывает объект обещания - я думал, что он будет записывать данные изображения, которые я назначил в обратном вызове. Редактировать: по какой-то причине исходный код не сохранялся, тот, что в этом комментарии, является новым, который я написал. – Soxad

+0

@Soxad, у вас есть другие проблемы. См. Обновленный ответ –