ng-repeat 내부의 지시문 사용 및 범위 '@'의 신비한 힘
작업 코드에서 질문을 보려면 여기에서 시작하십시오. http://jsbin.com/ayigub/2/edit
간단한 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;
}
};
});
자체적으로 사용되는 경우 두 지시문은 동일하게 작동하고 작동합니다.
<!-- This works -->
<div drink-shortcut flavor="blueberry"></div>
<hr/>
<!-- This works -->
<div drink-longhand flavor="strawberry"></div>
<hr/>
그러나 ng-repeat 내에서 사용하면 바로 가기 버전 만 작동합니다.
<!-- 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>
내 질문은 다음과 같습니다.
- longhand 버전이 ng-repeat 내에서 작동하지 않는 이유는 무엇입니까?
- ng-repeat 내에서 longhand 버전을 어떻게 작동시킬 수 있습니까?
에서는 drinkLonghand
코드를 사용합니다.
scope.flavor = attrs.flavor;
연결 단계에서 보간 된 속성은 아직 평가되지 않았으므로 해당 값은 undefined
입니다. (그들은 외부에서 작업 ng-repeat
하는 경우에 사용되지 않기 때문에 문자열 보간, 당신은 단지 일반 일반 문자열을 전달하고, 예를 들어, "딸기"를.) 이것은에서 언급 한 지침 개발자 가이드 의 방법과 함께, Attributes
그 존재하지 않는 API 문서에서 전화 $observe
:
$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
입니다. ( scope.flav = 'test';
위에에 대한 호출을 추가하여이를 테스트 할 수 있습니다 attrs.$observe
.)
물론 다음과 같은 격리 범위 정의를 사용하여이 문제를 해결할 수 있습니다.
scope: { flav: '@flavor' }
또는 비 격리 자식 범위를 만들어
scope: true
또는 template
with 에 의존하지 않고 {{flavor}}
대신 다음과 같은 직접적인 DOM 조작을 수행하십시오.
attrs.$observe('flavor', function(flavor) {
element.text(flavor);
});
but that defeats the purpose of the exercise (e.g. it'd be easier to just use the drinkShortcut
method). So, to make this directive work, we'll break out the $interpolate
service to do the interpolation ourself on the directive's $parent
scope:
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);
}
};
});
Of course, this only works for the initial value of scope.$parent.flav
; if the value is able to change, you'd have to use $watch
and reevaluate the result of the interpolate function fn
(I'm not positive off the top of my head how you'd know what to $watch
; you might just have to pass in a function). scope: { flavor: '@' }
is a nice shortcut to avoid having to manage all this complexity.
[Update]
To answer the question from the comments:
How is the shortcut method solving this problem behind the scenes? Is it using the $interpolate service as you did, or is it doing something else?
I wasn't sure about this, so I looked in the source. I found the following in 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;
}
So it seems that attrs.$observe
can be told internally to use a different scope than the current one to base the attribute observation on (the next to last line, above the break
). While it may be tempting to use this yourself, keep in mind that anything with the double-dollar $$
prefix should be considered private to Angular's private API, and is subject to change without warning (not to mention you get this for free anyway when using the @
mode).
'IT Share you' 카테고리의 다른 글
Android 색상 선택기 (0) | 2020.12.04 |
---|---|
Left shifting with a negative shift count (0) | 2020.12.04 |
$ http의 Angularjs 자동 완성 (0) | 2020.12.04 |
자바 8 : 병렬 FOR 루프 (0) | 2020.12.04 |
Collectors.toSet () 및 HashSet (0) | 2020.12.04 |