2013-10-17 7 views
11

ディレクティブのすべての(または一部の)属性の後にコールバックを1回だけ実行することは可能でしょうか?属性は、設定をディレクティブに渡すのに本当に素晴らしいものです。つまり、各属性を個別に監視し、コールバックを何回か実行できるということです。

この例では、名前と姓の2つの属性を観測する分離スコープのないディレクティブがあります。変更後actionコールバックが発射される:

HTML

<button ng-click="name='John';surname='Brown'">Change all params</button> 
<div person name="{{name}}" surname="{{surname}}"></div> 

JS

angular.module('app', []). 

directive('person', function() { 
    return { 
    restrict: 'A', 
    link: function($scope, $elem, $attrs) { 
     var action = function() { 
      $elem.append('name: ' + $attrs.name + '<br/> surname: ' + $attrs.surname+'<br/><br/>'); 
     } 
     $attrs.$observe('name', action); 
     $attrs.$observe('surname', action); 
    } 
} 
}); 

Plunker here

ので効果はワンクリック時に名前と名字を変更した後、actionコールバックが二回発射されていることである。

name: 
surname: Brown 

name: John 
surname: Brown 

そこで質問です:action名と姓の値を変更し、両方で1回のみ起動することができますか?

答えて

11

$watchを使用すると、特定のモデルではなくカスタム関数を評価できます。

すべて$digestサイクル上で実行され、$watchが検出された場合、戻り配列(またはただし、あなたの関数の戻り値を構築したいが)古い値と一致しない、コールバック

$scope.$watch(function() { 
    return [$attrs.name, $attrs.surname]; 
}, action, true); 

すなわち引数は$watchになります。オブジェクトを戻り値として使用する場合は、最後の引数のtrueの値を$watchのままにして、$watchが深い比較を行うようにしてください。

+0

はありがとうございました! – iamtankist

0

アンダースコア(またはlo-dash)は、once関数を持ちます。 onceの中に関数をラップすると、関数が1回だけ呼び出されるようにすることができます。

angular.module('app', []). 

directive('person', function() { 
    return { 
    restrict: 'A', 
    link: function($scope, $elem, $attrs) { 
     var action = function() { 
      $elem.append('name: ' + $attrs.name + '<br/> surname: ' + $attrs.surname+'<br/><br/>'); 
     } 
     var once = _.once(action); 
     $attrs.$observe('name', once); 
     $attrs.$observe('surname', once); 
    } 
} 
}); 
+2

残念ながら、 '_.once'はコールバックを1回だけ起動しますが、最初の属性が変更された場合のみ呼び出します。私のポイントは、単一の '$ digest'フェーズ中にすべての変更が行われた後にコールバックが起動されるべきです。 – kseb

0

だから、私は1つのコールスタック中の属性のいくつかの変更を待つことができobserveAll方法、私の独自の実装になってしまってきました。しかし、私はパフォーマンスについては分かりません。

@cmwのソリューションは単純なようですが、オブジェクトの等価性が何度も評価されると、多数のパラメータと複数の$ digestフェーズの実行でパフォーマンスが低下する可能性があります。しかし私は彼の答えを受け入れることに決めました。

angular.module('utils.observeAll', []). 

factory('observeAll', ['$rootScope', function($rootScope) { 
    return function($attrs, callback) { 
     var o = {}, 
      callQueued = false, 
      args = arguments, 

      observe = function(attr) { 
       $attrs.$observe(attr, function(value) { 
        o[attr] = value; 
        if (!callQueued) { 
         callQueued = true; 
         $rootScope.$evalAsync(function() { 
          var argArr = []; 
          for(var i = 2, max = args.length; i < max; i++) { 
           var attr = args[i]; 
           argArr.push(o[attr]); 
          } 
          callback.apply(null, argArr); 
          callQueued = false; 
         }); 
        } 
       }); 
      }; 

     for(var i = 2, max = args.length; i < max; i++) { 
      var attr = args[i]; 
      if ($attrs.$attr[attr]) 
       observe(attr); 
     } 
    }; 
}]); 

そして、あなたはあなたの指示でそれを使用することができます:あなたは私のアプローチを見ることができます

0

angular.module('app', ['utils.observeAll']). 

directive('person', ['observeAll', function(observeAll) { 
    return { 
    restrict: 'A', 
    link: function($scope, $elem, $attrs) { 
     var action = function() { 
      $elem.append('name: ' + $attrs.name + '<br/> surname: ' + $attrs.surname+'<br/><br/>'); 
     } 
     observeAll($attrs, action, 'name', 'surname'); 
    } 
} 
}]); 

Plunker here私が使用していた正確に同じ問題を解決別のアプローチを探していましたが、私は別のアプローチを探していました。 cmwの提案はうまくいきましたが、私はそのパフォーマンスを私のものと比較し、$ watchメソッドが何度も呼び出されているのを見たので、実装した方法を維持することに決めました。

私は追跡したいと思っていた両方の変数に対して$ observeを追加してデバウンス呼び出しにバインドしました。この問題を解決するために提示し、いくつかの方法があります

var debounceUpdate = _.debounce(function() { 
    setMinAndMaxValue(attrs['minFieldName'], attrs['maxFieldName']); 
}, 100); 

attrs.$observe('minFieldName', function() { 
    debounceUpdate(); 
}); 

attrs.$observe('maxFieldName', function() { 
    debounceUpdate(); 
}); 
0

:彼らの両方が非常にわずかな時間差で修正されているので、両方の$観察する方法は、短い遅延の後に実行されます同じ関数呼び出しをトリガ。私はデバウンスの解決策が大好きでした。しかし、ここに私のこの問題に対する解決策があります。これは1つの属性内のすべての属性を結合し、興味のある属性のJSON表現を作成します。今度は、$属性を1つだけ観察し、良いperfも必要です。ここで

は実装と、元plunkrのフォークです: linkhttp://plnkr.co/edit/un3iPL2dfmSn1QJ4zWjQ

関連する問題