その値が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専用のものであり、警告なしに変更されることに注意してください。 @
モード)。
ブランドン、これは本当に素晴らしい答えです、ありがとうございます。ちょうど1つのフォローアップの質問(編集として追加する気軽に):どのようにショートカット方法は、この問題を舞台裏で解決していますか?あなたがしたように$ interpolateサービスを使用していますか、それとも何か他のことをしていますか? – Jonah
ありがとう!あなたがそう思ってうれしい。私はそれについて確信が持てませんでしたので、私は解決策を見つけて答えを更新しました。 –
もう一度ありがとうございます。それはまさに私がSOで受け取ったやや難しい質問への最も徹底的な答えの一つであり、私が探していたものです。私はもっとそれをupvoteすることができれば願っています。しかし、あなたは、私が今朝から尋ねたこの質問に興味を持っているかもしれません、角度のドキュメントの潜在的なエラー、おそらくこれよりも答えが簡単です:http://stackoverflow.com/questions/16495684/angular-コントローラ - どのようにこれらの魔法の方法 - 作業中のユニットテスト – Jonah