2013-05-11 3 views
60

あなたはここから始め、コードを作業中に質問を確認する場合:http://jsbin.com/ayigub/2/editngのリピート内のディレクティブを使用して、スコープの神秘的な力「@」

は、単純なdireciveを書くために、このほぼ同等な方法を考えてみましょう:単独で使用する場合

app.directive("drinkShortcut", function() { 
    return { 
    scope: { flavor: '@'}, 
    template: '<div>{{flavor}}</div>' 
    }; 
}); 

app.directive("drinkLonghand", function() { 
    return { 
    scope: {}, 
    template: '<div>{{flavor}}</div>', 
    link: function(scope, element, attrs) { 
     scope.flavor = attrs.flavor; 
    } 
    }; 
}); 

、2つのディレクティブは、仕事と同じ動作:

<!-- This works --> 
    <div drink-shortcut flavor="blueberry"></div> 
    <hr/> 

    <!-- This works --> 
    <div drink-longhand flavor="strawberry"></div> 
    <hr/> 

しかし、NGリピート内で使用される、唯一のshortcをUTのバージョンは動作します:

<!-- Using the shortcut inside a repeat also works --> 
    <div ng-repeat="flav in ['cherry', 'grape']"> 
    <div drink-shortcut flavor="{{flav}}"></div> 
    </div> 
    <hr/> 

    <!-- HOWEVER: using the longhand inside a repeat DOESN'T WORK -->  
    <div ng-repeat="flav in ['cherry', 'grape']"> 
    <div drink-longhand flavor="{{flav}}"></div> 
    </div> 

私の質問は以下のとおりです。

  1. なぜ手書きのバージョンは、繰り返しngの内部で動作しませんか?
  2. どのようにして、ng-repeatの中で長さの変更ができますか? drinkLonghand

答えて

100

その値がundefinedているので、あなたがリンクフェーズ中にコード

scope.flavor = attrs.flavor; 

を使用し、補間された属性は、まだ、評価されていません。 (ng-repeatの外で動作するのは、文字列補間を使用していないため、普通の普通の文字列、例えば「strawberry」などを渡すだけなので)。Directives developer guideに記載されています。Attributes現在$observeと呼ばin the API documentationではありません。

使用$observe補間(例えばsrc="{{bar}}")を含む属性の値の変化を観察します。これは非常に効率的であるだけでなく、実際の値を簡単に取得する唯一の方法でもあります。リンクフェーズではまだ補間が評価されていないため、この時点で値はundefinedに設定されています。

ので、にこの問題を解決するために、あなたのdrinkLonghandディレクティブは次のようになります。

app.directive("drinkLonghand", function() { 
    return { 
    template: '<div>{{flavor}}</div>', 
    link: function(scope, element, attrs) { 
     attrs.$observe('flavor', function(flavor) { 
     scope.flavor = flavor; 
     }); 
    } 
    }; 
}); 

しかし、これに伴う問題は、それが分離株スコープを使用していないということです。このように、ライン

scope.flavor = flavor; 

flavorという名前の範囲を既存の変数を上書きする可能性を秘めています。ブランクの分離スコープを追加することもできません。 Angularは、flavという属性がないディレクティブのスコープに基づいて文字列を補間しようとするためです。 (attrs.$observeの呼び出しの上にscope.flav = 'test';を追加することでこれをテストできます。もちろん)

、あなたは

scope: true 

かによって

template {{flavor}}とに頼らない

scope: { flav: '@flavor' } 

のような分離株スコープ定義または非分離株の子スコープを作成することによってこの問題を解決することができ代わりにDOMのような直接的なDOM操作を行うようにしてください。

attrs.$observe('flavor', function(flavor) { 
    element.text(flavor); 
}); 

しかし、それは運動の目的を敗北させる(例。単にdrinkShortcutメソッドを使用する方が簡単です)。ですから、このディレクティブの仕事をするために、我々は、ディレクティブの$parent範囲に補間に私たち自身を行うに$interpolate serviceを破るよ:もちろん

app.directive("drinkLonghand", function($interpolate) { 
    return { 
    scope: {}, 
    template: '<div>{{flavor}}</div>', 
    link: function(scope, element, attrs) { 
     // element.attr('flavor') == '{{flav}}' 
     // `flav` is defined on `scope.$parent` from the ng-repeat 
     var fn = $interpolate(element.attr('flavor')); 
     scope.flavor = fn(scope.$parent); 
    } 
    }; 
}); 

scope.$parent.flavの初期値については、この唯一の作品。値が変更できる場合は、use $watchにして、補間関数fnの結果を再評価する必要があります(私は自分の頭の中で何を知っているかわからないので、$watchに渡す必要があります。関数内で)。 scope: { flavor: '@' }は、このような複雑さをすべて管理する必要を避けるための素敵なショートカットです。

[更新]

コメントからの質問に答えるために:

舞台裏で、この問題を解決するショートカットメソッドでどのように?あなたがしたように$ interpolateサービスを使用していますか、それとも何か他のことをしていますか?

私はソースを調べました。私はcompile.jsで、次を発見した:

forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) { 
    var match = definiton.match(LOCAL_REGEXP) || [], 
     attrName = match[2]|| scopeName, 
     mode = match[1], // @, =, or & 
     lastValue, 
     parentGet, parentSet; 

    switch (mode) { 

    case '@': { 
     attrs.$observe(attrName, function(value) { 
     scope[scopeName] = value; 
     }); 
     attrs.$$observers[attrName].$$scope = parentScope; 
     break; 
    } 

だから、attrs.$observeは(break上記、最後の行の次)上の属性の観察をベースに、現在のものとは異なるスコープを使用するために内部伝えることができるようです。これを自分自身で使用することが魅力的かもしれませんが、二重ドルの$$接頭辞が付いているものは、AngularのプライベートAPI専用のものであり、警告なしに変更されることに注意してください。 @モード)。

+0

ブランドン、これは本当に素晴らしい答えです、ありがとうございます。ちょうど1つのフォローアップの質問(編集として追加する気軽に):どのようにショートカット方法は、この問題を舞台裏で解決していますか?あなたがしたように$ interpolateサービスを使用していますか、それとも何か他のことをしていますか? – Jonah

+0

ありがとう!あなたがそう思ってうれしい。私はそれについて確信が持てませんでしたので、私は解決策を見つけて答えを更新しました。 –

+1

もう一度ありがとうございます。それはまさに私がSOで受け取ったやや難しい質問への最も徹底的な答えの一つであり、私が探していたものです。私はもっ​​とそれをupvoteすることができれば願っています。しかし、あなたは、私が今朝から尋ねたこの質問に興味を持っているかもしれません、角度のドキュメントの潜在的なエラー、おそらくこれよりも答えが簡単です:http://stackoverflow.com/questions/16495684/angular-コントローラ - どのようにこれらの魔法の方法 - 作業中のユニットテスト – Jonah

関連する問題