Подтвердить что ты не робот

AngularJS - привязка к размеру директивы

Как я могу получать уведомления о изменении размера директивы? я пробовал

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

но не вызывая функцию

(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) {

    }
}

      })();
4b9b3361

Ответ 1

Используйте область. $watch с пользовательской функцией часов:

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

Ответ 2

Обычно вам нужно посмотреть свойства элемента offsetWidth и offsetHeight. В более поздних версиях AngularJS вы можете использовать $scope.$watchGroup в своей функции ссылок:

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 ...

}]);

Однако вы можете обнаружить, что обновления довольно медленны при непосредственном просмотре свойств элемента таким образом.

Чтобы сделать вашу директиву более отзывчивой, вы можете уменьшить частоту обновления, используя $interval. Здесь приведен пример многоразовой службы для просмотра размеров элементов с настраиваемой миллисекундной скоростью:

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); };
    };
}]);

Директива, использующая такую ​​услугу, будет выглядеть примерно так:

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 ...

}]);

Обратите внимание на вызов watcher.cancel() в обработчике событий $scope.$destroy; это гарантирует, что экземпляр $interval будет уничтожен, когда это больше не требуется.

Пример JSFiddle можно найти здесь.

Ответ 3

Вот пример кода, который вам нужно сделать:

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();
      });
    }
  };
});

Ответ 4

Единственный способ определить изменения размера и положения элемента с помощью $watch - если вы постоянно обновляете свою область, используя что-то вроде $interval или $timeout. Хотя возможно, это может стать дорогостоящей операцией и действительно замедлить ваше приложение.

Одним из способов обнаружения изменения элемента является вызов 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...
}

Здесь Plunk демонстрирует это. Пока вы перемещаете коробку, она останется красной.

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

Ответ 5

Небольшая вариация ответа Элиэля сработала для меня. В директиве .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();
      });

Я звоню

    $(window).resize();

из моего приложения. Теперь директива d3 изменит размер, чтобы заполнить контейнер.

Ответ 6

Вот моя рекомендация по этой директиве (используя Webpack как 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
  ]