web-dev-qa-db-fra.com

AngularJS - lie à la directive redimensionner

Comment puis-je être averti lorsqu'une directive est redimensionnée? J'ai essayé 

element[0].onresize = function() {
            console.log(element[0].offsetWidth + " " + element[0].offsetHeight);
        }

mais sa fonction n'appelle pas

(function() {
'use strict';

// Define the directive on the module.
// Inject the dependencies. 
// Point to the directive definition function.
angular.module('app').directive('nvLayout', ['$window', '$compile', layoutDirective]);

function layoutDirective($window, $compile) {
    // Usage:
    // 
    // Creates:
    // 
    var directive = {
        link: link,
        restrict: 'EA',
        scope: {
            layoutEntries: "=",
            selected: "&onSelected"
        },
        template: "<div></div>",
        controller: controller
    };
    return directive;

    function link(scope, element, attrs) {
        var elementCol = [];

        var onSelectedHandler = scope.selected();

        element.on("resize", function () {
            console.log("resized.");
        });

        $(window).on("resize",scope.sizeNotifier);

        scope.$on("$destroy", function () {
            $(window).off("resize", $scope.sizeNotifier);
        });

        scope.sizeNotifier = function() {
            alert("windows is being resized...");
        };

        scope.onselected = function(id) {
            onSelectedHandler(id);
        };



        scope.$watch(function () {
            return scope.layoutEntries.length;
        },
        function (value) {
            //layout was changed
            activateLayout(scope.layoutEntries);
        });

        function activateLayout(layoutEntries) {


            for (var i = 0; i < layoutEntries.length; i++) {

                if (elementCol[layoutEntries[i].id]) {
                    continue;
                }
                var div = "<nv-single-layout-entry id=slot" + layoutEntries[i].id + " on-selected='onselected' style=\"position:absolute;";
                div = div + "top:" + layoutEntries[i].position.top + "%;";
                div = div + "left:" + layoutEntries[i].position.left + "%;";
                div = div + "height:" + layoutEntries[i].size.height + "%;";
                div = div + "width:" + layoutEntries[i].size.width + "%;";
                div = div + "\"></nv-single-layout-entry>";

                var el = $compile(div)(scope);
                element.append(el);
                elementCol[layoutEntries[i].id] = 1;
            }


        };
    }

    function controller($scope, $element) {

    }
}

      })();
22
li-raz

Utilisez scope. $ Watch avec une fonction de surveillance personnalisée:

scope.$watch(
  function () {
    return [element[0].offsetWidth, element[0].offsetHeight].join('x');
  },
  function (value) {
    console.log('directive got resized:', value.split('x'));
  }
)
15
epegzz

Vous voudriez généralement voir les propriétés offsetWidth et offsetHeight de l'élément. Avec les versions plus récentes d'AngularJS, vous pouvez utiliser $scope.$watchGroup dans votre fonction de lien:

app.directive('myDirective', [function() {

    function link($scope, element) {
        var container = element[0];

        $scope.$watchGroup([
            function() { return container.offsetWidth; },
            function() { return container.offsetHeight; }
        ],  function(values) {
              // Handle resize event ...
        });
    }

    // Return directive definition ...

}]);

Cependant, vous constaterez peut-être que les mises à jour sont assez lentes lorsque vous visualisez directement les propriétés de l'élément de cette manière.

Pour rendre votre directive plus réactive, vous pouvez modérer le taux de rafraîchissement en utilisant $interval. Voici un exemple de service réutilisable permettant de surveiller la taille des éléments à une vitesse configurable en millisecondes:

app.factory('sizeWatcher', ['$interval', function($interval) {
    return function (element, rate) {
        var self = this;
        (self.update = function() { self.dimensions = [element.offsetWidth, element.offsetHeight]; })();
        self.monitor = $interval(self.update, rate);
        self.group = [function() { return self.dimensions[0]; }, function() { return self.dimensions[1]; }];
        self.cancel = function() { $interval.cancel(self.monitor); };
    };
}]);

Une directive utilisant un tel service ressemblerait à ceci:

app.directive('myDirective', ['sizeWatcher', function(sizeWatcher) {

    function link($scope, element) {
        var container = element[0],
            watcher = new sizeWatcher(container, 200);

        $scope.$watchGroup(watcher.group, function(values) {
            // Handle resize event ...
        });

        $scope.$on('$destroy', watcher.cancel);
    }

    // Return directive definition ...

}]);

Notez l'appel à watcher.cancel() dans le gestionnaire d'événements $scope.$destroy; cela garantit que l'instance $interval est détruite lorsqu'elle n'est plus requise.

Un exemple de JSFiddle peut être trouvé ici .

13
SimonSparks

Voici un exemple de code de ce que vous devez faire: 

APP.directive('nvLayout', function ($window) {
  return {
    template: "<div></div>",
    restrict: 'EA',
    link: function postLink(scope, element, attrs) {

      scope.onResizeFunction = function() {
        scope.windowHeight = $window.innerHeight;
        scope.windowWidth = $window.innerWidth;

        console.log(scope.windowHeight+"-"+scope.windowWidth)
      };

      // Call to the function when the page is first loaded
      scope.onResizeFunction();

      angular.element($window).bind('resize', function() {
        scope.onResizeFunction();
        scope.$apply();
      });
    }
  };
});
7
Eliel Haouzi

La seule façon pour vous de détecter les changements de taille/position sur un élément à l'aide de $ watch est si vous mettez constamment à jour votre étendue en utilisant quelque chose comme $ interval ou $ timeout. Si possible, cela peut devenir une opération coûteuse et ralentir votre application.

Une façon de détecter un changement sur un élément consiste à appeler requestAnimationFrame.

var previousPosition = element[0].getBoundingClientRect();

onFrame();

function onFrame() {
  var currentPosition = element[0].getBoundingClientRect();

  if (!angular.equals(previousPosition, currentPosition)) {
    resiszeNotifier();
  }

  previousPosition = currentPosition;
  requestAnimationFrame(onFrame);
}

function resiszeNotifier() {
  // Notify...
}

Voici un Plunk qui le démontre. Tant que vous déplacez la boîte, elle restera rouge.

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

2
Blake Bowen

Voici mon point de vue sur cette directive (en utilisant Webpack comme bundler):

module.exports = (ngModule) ->

  ngModule.directive 'onResize', ['Callback', (Callback) ->
    restrict: 'A'
    scope:
      onResize: '@'
      onResizeDebounce: '@'
    link: (scope, element) ->
      container = element[0]
      eventName = scope.onResize || 'onResize'
      delay = scope.onResizeDebounce || 1000
      scope.$watchGroup [
        -> container.offsetWidth ,
        -> container.offsetHeight
      ], _.debounce (values) ->
        Callback.event(eventName, values)
      , delay
  ]
0
Kamil

Une légère variation de la réponse d'Eliel a fonctionné pour moi. Dans la directive.js:

      $scope.onResizeFunction = function() {
      };

      // Call to the function when the page is first loaded
      $scope.onResizeFunction();

      angular.element($(window)).bind('resize', function() {
        $scope.onResizeFunction();
        $scope.$apply();
      });

J'appelle

    $(window).resize();

depuis mon app.js. Le graphique d3 de la directive est maintenant redimensionné pour remplir le conteneur.

0
Matt Bearson