2014-01-16 22 views
21

ディレクティブのサイズが変更されたときにどのように通知できますか? 私は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) { 

    } 
} 

     })(); 
+0

私は、コードの目的を理解しようとしたが、それは私には難しいです。私はあなたのコードのJQueryの依存関係を排除しており、ここで確認することができます:http://jsfiddle.net/U3pVM/2669/ –

+0

私は、ディレクティブの要素のサイズが変更されたときに通知を受けようとしています。私はページ全体を聞くことができますが、いつelemntが指示を移動させるのか知りたがっています –

+0

@ li-raz:[私の答え](http://stackoverflow.com/a/23031644/434989)はそれを正確に達成します:-) – epegzz

答えて

7

あなたが何をする必要があるかのサンプルコード関数を呼び出していない:カスタムウォッチ機能と

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

ディレクティブのサイズが変更されただけで、ウィンドウ自体はサイズ変更されない場合、これは機能しません。 – epegzz

+0

バインドは私のために働いています...あなたはapplyを呼び出す必要はないとは思いますが –

14

使用scope.$watchを:

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

私はこれを試しましたが、通常は古い値を表示します。私はボタンを使って非表示にすることができるサイドバーを持っています。クリックすると、ダイジェストサイクルが発生し、ウォッチ機能は、要素のサイズが変更されなかったことを通知し、要素がサイズ変更され、これは不具合を引き起こす。何か案は? –

+1

@HernanRajchert(および他の将来の読者)、それは_ [clientHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight)がCSSの高さ+ CSSパディング - 水平スクロールバーの高さ(存在する場合)._必要なものは[.offsetHeight](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.offsetHeight)です。 'element [0] .offsetHeight'(およびwidth)を見ることはうまくいくはずです。 –

+0

@ JordanCarroll私にとっては、clientHeightではなくoffsetHeightを使っても問題は解決しませんでした。 – nardnob

2

$ watchを使って要素のサイズ/位置の変更を検出できる唯一の方法は、$ intervalや$ timeoutのようなものを使ってスコープを絶えず更新しているかどうかです。可能であれば、それは高価な操作になる可能性があり、本当にあなたのアプリケーションを遅くする。

要素の変更を検出できる方法の1つは、 ​​を呼び出すことです。

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

ここでは、このことを実証している愚か者です。あなたが箱を動かす限り、それは赤く留まるでしょう。

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

12

通常は、要素のoffsetWidthoffsetHeightプロパティを見たいと思うでしょう。 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の例はhereです。

+3

このメソッドを使いたい人は、 '$ interval(self.update、rate);'を '$ interval(self.update、rate、0、false);'に置き換えることを検討してください。 。それ以外の場合、スコープのダイジェストは各インターバルコールバック関数呼び出しで呼び出されます。あなたは '$ scope。$ watch(function(){console.log(" invalidated ");});' –

0

エリエルの答えにわずかな違いがありました。 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(); 
     }); 

私はapp.js.内から

$(window).resize(); 

呼び出しますディレクティブのd3チャートは、コンテナを埋めるようにサイズ変更されるようになりました。ここで

0

は(バンドラとしてWebpackを使用して)このディレクティブが私の感想です:

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 
    ] 
関連する問題