web-dev-qa-db-fra.com

Angular JS et Directive Link et $ timeout

j'ai un problème avec un exemple très basique avec AngularJS et les directives. Je veux créer une directive qui montre une image webcam avec webrtc. Mon code affiche parfaitement le flux mais si j'ajoute un délai d'attente (par exemple pour rafraîchir un canevas) le délai d'attente $ ne fonctionne pas, c'est le code:

wtffDirectives.directive('scannerGun',function($timeout){
    return {
        restrict: 'E',
        template: '<div>' +
            '<video ng-hide="videoStatus"></video>' +
            '<canvas id="canvas-source"></canvas>' +               
            '</div>',
        replace: true,
        transclude: true,
        scope: false,
        link: function postLink($scope, element){
           $scope.canvasStatus = true;
           $scope.videoStatus = false;

           width = element.width = 320;
           height = element.height = 0;

           /* this method draw the webcam image into a canvas */
           var drawVideoCanvas = function(){
              sourceContext.drawImage(vid,0,0, vid.width, vid.height);
           };

           /* start the timeout that take a screenshot and draw the source canvas */
           var update = function(){
              var timeout = $timeout(function(){
                console.log("pass"); //the console log show only one "pass"
                //drawVideoCanvas();
              }, 2000);
           };

           /* this work perfectly and reproduct into the video tag the webcam */
           var onSuccess = function onSuccess(stream) {
              // Firefox supports a src object
              if (navigator.mozGetUserMedia) {
                 vid.mozSrcObject = stream;
              } else {
                 var vendorURL = window.URL || window.webkitURL;
                 vid.src = vendorURL.createObjectURL(stream);
              }
              /* Start playing the video to show the stream from the webcam*/
              vid.play();
              update();
           };

           var onFailure = function onFailure(err) {

              if (console && console.log) {
                console.log('The following error occured: ', err);
              }
              return;
           };

           var vid = element.find('video')[0];
           var sourceCanvas = element.find('canvas')[0];
           var sourceContext = sourceCanvas.getContext('2d');

           height = (vid.videoHeight / ((vid.videoWidth/width))) || 250;
           vid.setAttribute('width', width);
           vid.setAttribute('height', height);

           navigator.getMedia (
              // ask only for video
              {
                video: true,
                audio: false
              },
              onSuccess,
              onFailure
           );
         }
       }
    });

Quel est le problème? pourquoi le $ timeout ne fonctionne pas dans ces conditions? et enfin une solution?

merci d'avance

34
cingusoft

Dans votre code, votre commentaire indique "n'afficher qu'un seul" pass "". Le timeout ne s'exécute qu'une seule fois, après le délai spécifié.

Peut-être que vous voulez setInterval (si vous êtes pré angular 1.2)/$ interval (nouveau à 1.2) qui établit un appel récurrent. Voici la version setInterval:

var timeout = setInterval(function(){
    // do stuff
    $scope.$apply();
}, 2000); 

J'ai inclus $ apply pour rappeler que puisqu'il s'agit d'un appel jQuery externe, vous devez dire angular pour mettre à jour le DOM (si vous apportez les modifications appropriées). ($ Timeout étant un angular met automatiquement à jour le DOM)

14
KayakDave

Vous pouvez injecter des dépendances à la directive comme dans d'autres modules:

.directive('myDirective', ['$timeout', function($timeout) {
   return {
        ...
        link: function($scope, element){
            //use $timeout
        }
    };
}]);
78
Paweł Psztyć

Je ne sais pas si j'ai eu votre doute ici, mais $timeout est à peu près la même chose que la fonction javascript plain setTimeout, et elle n'est supposée être exécutée qu'une seule fois, contrairement à setInterval.

Si vous utilisez Angular 1.2.0, changez $timeout service par $interval . Si sinon vous êtes sur la version 1.0, vous pouvez la rendre récursive:

var timeout;
var update = function() {
  // clear previous interval
  timeout && timeout();
  timeout = $timeout(function() {
    // drawSomething(...);
    update();
  }, 2000);
}
5
Caio Cunha