AngularJS에서 지시문을 작성할 때 새로운 범위, 새로운 자식 범위 또는 새로운 격리 된 범위가 필요하지 않은지 어떻게 결정합니까?


265

새 지시문을 작성할 때 사용할 범위 유형을 결정하는 데 사용할 수있는 몇 가지 지침을 찾고 있습니다. 이상적으로, 나는 많은 질문을 안내하고 새로운 새로운 범위, 새로운 자식 범위 또는 새로운 격리 범위가 아닌 올바른 대답을 보여주는 흐름도와 비슷한 것을 원하지만 너무 많이 요구하는 것 같습니다. 다음은 현재의 팰 트리 가이드 라인입니다 :

요소에 격리 범위가있는 지시문을 사용하면 동일한 요소의 다른 모든 지시문이 동일한 (하나의) 격리 범위를 사용하게되므로 격리 범위를 사용할 수있을 때 이것이 심각하게 제한되지 않습니까?

Angular-UI 팀의 일부 (또는 많은 지시문을 작성한 다른 사람들)가 자신의 경험을 공유 할 수 있기를 바랍니다.

단순히 "재사용 가능한 구성 요소에 격리 된 범위 사용"이라는 답변을 추가하지 마십시오.


"자식 범위"란 링크 함수에서 "scope. $ new ()"로 범위를 만드는 것을 의미합니까? 때문에 내가 아는 한, 지시어는 범위를 격리 한 수 있거나이없는 (그래서 사용되는 범위를 사용하는 것)
Valentyn Shybanov

3
@ValentynShybanov Setting scope: true$scope.new()자동을 사용하여 자식 범위를 만듭니다 .
Josh David Miller

2
@Valentyn, Josh의 말 : 따라서 세 가지 가능성은 scope: false(기본, 새로운 범위 없음), scope: true(시제품을 상속하는 새로운 범위) 및 scope: { ... }(새로운 분리 범위)입니다.
Mark Rajcok

1
네, thnx. "true"와 "{}"의 차이점을 놓쳤습니다. 알아 둘만 한.
Valentyn Shybanov

.. 나는 질문이 ...뿐만 아니라 질문에 대한 +1을 포함하도록 확장되어야한다 생각 "지시문 컨트롤러가"사람들이 일반적으로 .. 무시하는 경향이 4 케이스가 .. 있습니다
ganaraj

답변:


291

정말 좋은 질문입니다! 나는 것 좋아하는 다른 사람이 무슨 말을하는지 듣고, 그러나 여기 내가 사용하는 지침입니다.

고도 전제 : 범위는 상위 컨트롤러, 지시문 및 지시문 템플릿간에 통신하는 데 사용되는 "접착제"로 사용됩니다.

부모 범위 : scope: false 이므로 전혀 새로운 범위가 없습니다.

나는 이것을 자주 사용하지 않지만 @MarkRajcok가 말했듯이 지시어가 범위 변수에 액세스하지 않으면 (그리고 분명히 설정되지 않았습니다!), 이것은 내가 걱정하는 한 괜찮습니다. 이것은 부모 지시문의 컨텍스트 에서만 사용되며 (항상 예외는 있지만) 템플릿이없는 자식 지시문에도 유용합니다 . 기본적으로 템플릿이있는 것은 범위를 공유하는 것이 아닙니다. 왜냐하면 본질적으로 액세스 및 조작을 위해 해당 범위를 노출하기 때문입니다 (그러나이 규칙에는 예외가 있다고 확신합니다).

예를 들어, 최근에는 작성중인 SVG 라이브러리를 사용하여 (정적) 벡터 그래픽을 그리는 지시문을 만들었습니다. 이 $observe두 가지 특성 (들 widthheight그 어느 세트) 및 용도의 계산에 해당하지만,이 범위도 임의의 변수를 판독하고, 어떤 템플릿이 없다. 다른 범위를 만들지 않는 좋은 사용 사례입니다. 우리는 필요하지 않으므로 왜 귀찮게합니까?

그러나 다른 SVG 지시문에서 사용할 데이터 세트가 필요했으며 추가로 약간의 상태를 저장해야했습니다. 이 경우 부모 범위를 사용하는 것은 무책임합니다 (다시 말해서). 그래서 대신에...

아동 범위 : scope: true

자식 범위가있는 지시문은 상황을 인식하며 현재 범위와 상호 작용하기위한 것입니다.

분명히, 격리 범위에 비해 이것의 주요 장점은 사용자가 원하는 속성에 대해 보간을 자유롭게 사용할 수 있다는 것입니다. 예를 들어 class="item-type-{{item.type}}"격리 범위와 함께 지시문을 사용하면 기본적으로 작동하지 않지만 보간 된 항목은 여전히 ​​기본적으로 부모 범위에서 찾을 수 있기 때문에 자식 범위가있는 지시문에서는 제대로 작동합니다. 또한 지시문 자체는 부모의 오염이나 손상에 대한 걱정없이 자체 범위의 맥락에서 속성과 표현을 안전하게 평가할 수 있습니다.

예를 들어 툴팁은 추가 된 것입니다. 격리 범위는 작동하지 않습니다 (기본적으로 아래 참조). 여기서 다른 지시문이나 보간 된 속성을 사용할 것으로 예상되기 때문입니다. 툴팁은 개선 된 기능입니다. 그러나 툴팁은 하위 지시문 및 / 또는 템플릿과 함께 사용하고 분명히 자체 상태를 관리하기 위해 범위에 몇 가지 사항을 설정해야하므로 실제로 부모 범위를 사용하는 것은 매우 나쁩니다. 우리는 그것을 오염 시키거나 손상시키고 있으며 부에노도 아닙니다.

독립 또는 부모 범위보다 자식 범위를 더 자주 사용합니다.

범위를 분리하십시오. scope: {}

재사용 가능한 구성 요소를위한 것입니다. :-)

그러나 심각하게도 "재사용 가능한 구성 요소"는 "자체 포함 된 구성 요소"라고 생각합니다. 의도는 특정 목적으로 사용되어야하기 때문에 다른 지시문과 결합하거나 다른 보간 속성을 DOM 노드에 추가하는 것은 본질적으로 의미가 없습니다.

보다 구체적으로,이 독립형 기능에 필요한 모든 것은 상위 범위의 컨텍스트에서 평가 된 지정된 속성을 통해 제공됩니다. 단방향 문자열 ( '@'), 단방향 표현식 ( '&') 또는 양방향 변수 바인딩 ( '=')입니다.

자체 포함 된 구성 요소에서는 다른 지시문이나 속성이 자체적으로 존재하기 때문에 적용 할 필요가 없습니다. 스타일은 자체 템플릿 (필요한 경우)에 따라 결정되며 필요한 경우 적절한 내용을 포함 할 수 있습니다. 독립형이므로 격리 범위에 배치하여 "이 문제를 해결하지 마십시오. 몇 가지 속성을 통해 정의 된 API를 제공합니다."

가장 좋은 방법은 지시문 링크 및 컨트롤러 기능에서 가능한 많은 템플릿 기반 항목을 제외하는 것입니다. 이는 또 다른 "API와 같은"구성 지점을 제공합니다. 지시문의 사용자는 단순히 템플릿을 바꿀 수 있습니다! 기능은 모두 동일하게 유지되었으며 내부 API는 절대 손대지 않았지만 필요한만큼 스타일과 DOM 구현을 망칠 수 있습니다. ui / bootstrap은 Peter & Pawel이 훌륭하기 때문에 이것을 잘하는 좋은 예입니다.

격리 범위도 변환과 함께 사용하기에 좋습니다. 탭을 가지고; 그것들은 전체 기능 일뿐만 아니라 그 안에 있는 모든 것을 부모 범위 내에서 자유롭게 평가할 수 있으며 원하는대로 탭과 창을 남겨 둡니다. 탭은 분명히 자신의 상태 를 가지고 있으며, 이는 템플릿과 상호 작용하기 위해 범위에 속하지만 해당 상태는 사용 된 컨텍스트와 아무런 관련이 없습니다. 탭 지시문을 탭 지시문으로 만드는 것은 전적으로 내부적입니다. 또한 탭과 함께 다른 지시문을 사용하는 것은 의미가 없습니다. 그것들은 탭입니다-우리는 이미 그 기능을 가지고 있습니다!

더 많은 기능으로 둘러싸거나 더 많은 기능을 포함 시키지만 지시문은 이미 그 기능입니다.

그러나 @ProLoser가 그의 대답에서 암시 한 것처럼 격리 범위의 일부 제한 (예 : 기능)을 둘러싼 방법이 있음에 유의해야합니다. 예를 들어 자식 범위 섹션에서 격리 범위를 사용할 때 비 기본 속성 파괴에 대한 보간에 대해 언급했습니다 (기본적으로). 그러나 사용자는 예를 들어 간단하게 사용할 수 class="item-type-{{$parent.item.type}}"있으며 다시 작동합니다. 따라서 하위 범위에 대해 격리 범위를 사용해야하는 강력한 이유가 있지만 이러한 제한 중 일부에 대해 걱정이되는 경우 필요한 경우 거의 모든 문제를 해결할 수 있습니다.

요약

새로운 범위가없는 지시문은 읽기 전용입니다. 그들은 완전히 신뢰할 수 있으며 (즉, 앱 내부) 잭을 만지지 않습니다. 자식 범위가있는 지시문은 기능을 추가 하지만 유일한 기능 은 아닙니다 . 마지막으로 격리 범위는 전체 목표 인 지시문에 대한 것입니다. 그것들은 독립형이기 때문에, 그들이 도둑질을하는 것은 괜찮습니다.

나는 초기 생각을 꺼내고 싶었지만 더 많은 것을 생각할 때 이것을 업데이트 할 것입니다. 그러나 거룩한 쓰레기-이것은 SO 답변을 기다리는 데 오래입니다 ...


추신 : 완전히 접선이지만 범위에 대해 이야기하고 있기 때문에 나는 "프로토 타입"이라고 말하고 다른 사람들은 "프로토 타입"을 선호합니다. :-)


고마워 조쉬, 좋은 대답입니다. 나는 이것에 대한 긴 대답을 원했습니다. 내가 따르지 않은 두 가지 : 1) 자식 범위 : "사용자는 원하는 속성에 대해 보간을 자유롭게 사용할 수 있습니다". 2) 격리 범위 : "또는 모든 경우에 '?'의 경우"일부를 자세히 설명 할 수 있습니까? (더 쉬운 경우 의견을 작성하는 대신 게시물을 자유롭게 편집하십시오.)
Mark Rajcok

@MarkRajcok (1)의 경우, 조금 덜 애매하게 만들기 위해 변경했습니다. 실패한 경우 알려주십시오. (2)의 경우, 오타와 나쁜 표현이 결합되었습니다. 나는 그 단락을 더 명확하게 다시 썼다. 또한 추가 예제를 추가하고 몇 가지 사항을 더 명확하게하고 오타를 수정했습니다.
Josh David Miller

답변에서 언급했듯이-앵귤러 부트 스트랩은 이러한 조합의 좋은 예입니다. 나는 아코디언 예제가 특히 유용하다는 것을 발견했다
-GitHub-

하위 범위를 가장 많이 사용한다고 언급했으며 재사용 가능한 지시문 패턴이 가장 일반적이라고 생각했으며 한 번만 사용해야하는 지시문 작성을 피했습니다. 이것이 불필요합니까? 때로는 HTML이 너무 커지면 해당 섹션을 지시문으로 옮기는 느낌이 들지만 한 번만 사용되므로 HTML로 그대로 두십시오.
user2483724

2
@ user2483724 가장 일반적인 오해는 "재사용 가능한"지시문이 분리 범위를 사용하는 것입니다. 별로. 사전 패키징 된 지시문을 보면 거의 아무도 격리 범위를 사용하지 않습니다. 일부는 하위 범위도 아니지만 재사용 할 수 있습니다. 규칙은 지시문 내의 범위가 사용되는 방식에 있어야합니다. 파일의 공간을 절약하려는 경우 지시문이 최선의 방법인지 확실하지 않습니다. 개발자를 위해 처리 시간이 늘어납니다. 그러나 당신이해야한다면, 가십시오. 또는을 사용하십시오 ngInclude. 또는 빌드의 일부로 수행하십시오. 많은 옵션!
Josh David Miller

52

나의 개인적인 정책과 경험 :

절연 : 개인 샌드 박스

내 지시어에서만 사용되며 사용자가 직접 보거나 직접 액세스하지 않는 많은 범위 메서드와 변수를 만들고 싶습니다. 사용 가능한 스코프 데이터를 허용하고 싶습니다. transclusion을 사용하여 사용자가 부모 범위에서 영향을받지 않도록 할 수 있습니다 (영향 없음) . 나는 포함 된 자식에서 변수와 메소드에 접근하기를 원하지 않습니다 .

아동 : 콘텐츠의 하위 섹션

사용자가 액세스 할 있는 스코프 메소드와 변수를 만들고 싶지만 내 지시문의 맥락 밖에서 주변 스코프 (형제 및 부모)와 관련이 없습니다. 또한 모든 부모 범위 데이터가 투명하게 세분화되도록하고 싶습니다.

없음 : 단순 읽기 전용 지시문

스코프 메소드 또는 변수를 엉망으로 만들 필요가 없습니다. 아마도 범위와 관련이없는 작업 (예 : 간단한 jQuery 플러그인 표시, 유효성 검사 등)을하고있을 것입니다.

노트

  • ngModel 또는 기타 사항이 결정에 직접 영향을 미치지 않도록하십시오. ng-model=$parent.myVal(자식) 또는 ngModel: '='(격리) 와 같은 일을 수행하여 이상한 행동을 피할 수 있습니다 .
  • Isolate + transclude 는 모든 정상적인 동작을 형제 지시문으로 복원하고 부모 범위로 돌아갑니다. 따라서 판단에 영향을 미치지 않도록하십시오.
  • 의 범위를 함께 엉망를 수행 없음 이 바닥은 DOM의 절반이 아닌 0 의미가 상단의 절반 범위에 데이터를 넣어처럼 때문이다.
  • 지시 우선 순위에주의를 기울이십시오 (이것이 어떻게 영향을 미칠 수 있는지에 대한 구체적인 예는 없습니다)
  • 서비스를 주입하거나 컨트롤러를 사용하여 모든 범위 유형의 지시문간에 통신하십시오. require: '^ngModel'부모 요소를 살펴볼 수도 있습니다 .

1
이 부분을 오해했을 수도 있습니다. "격리 + transclude는 모든 정상적인 동작을 형제 지시문으로 복원합니다." 참조 이 plunker을 . 콘솔을 살펴 봐야합니다.
Josh David Miller

1
귀하의 통찰력 / 응답에 감사드립니다. angularjs-ui 태그를 추가하면이 게시물을 보길 원하는 사람들 중 하나입니다.
Mark Rajcok

@JoshDavidMiller 같은 DOM 요소에 대한 지시문에 대해 이야기 할 때 더 복잡해지며 우선 순위 속성을 살펴 봐야합니다. 번역은 어린이의 내용과 관련이 있습니다.
ProLoser 2013

1
@ProLoser 맞습니다.하지만 그 말의 의미를 잘 모르겠습니다. 그들은 분명히 어린이들에게 영향을 주지만, 지시문의 범위는 그들의 형제 지시문에 어떤 영향을 미칩니 까?
Josh David Miller

18

많은 지시문을 작성한 후, 나는 더 적은 isolated범위 를 사용하기로 결정했습니다 . 시원하고 데이터를 캡슐화하고 부모 범위로 데이터를 유출하지 않더라도 함께 사용할 수있는 지시문의 양을 심각하게 제한합니다. 그래서,

작성하려는 지시문이 완전히 자체적 으로 작동 하고 다른 지시문과 공유하지 않으려면 격리 범위 로 이동하십시오 . (구성 요소와 같이 최종 개발자를 위해 많은 사용자 정의를하지 않고도 플러그인 할 수 있음) (지시문이있는 하위 요소를 작성하려고하면 매우 까다로워집니다)

당신이 쓰기에 가고있는 지시어에가는 경우 단지 어떤 범위의 내부 상태, 또는 명시 적 범위 변경 (대부분 매우 간단한 일)가 필요 없다 DOM 조작을 할; 새로운 범위찾지 마십시오 . (예를 들면 ngShow, ngMouseHover, ngClick, ngRepeat)

작성하려는 지시문이 부모 범위의 일부 요소를 변경해야하지만 일부 내부 상태도 처리 해야하는 경우 new child scope 로 이동하십시오 . (예 ngController)

지침에 대한 소스 코드를 확인하십시오 : https://github.com/angular/angular.js/tree/master/src/ng/directive
이 크게 그들에 대해 생각하는 방법에 대한 도움


여러 구성 요소가 서로 통신해야하는 경우 격리 된 범위와 사용을 가질 수 require있으므로 지시문을 계속 분리하십시오. 그렇다면 어떻게 가능성을 제한합니까? 지시문을보다 구체적으로 만듭니다 (따라서 의존하는 것을 선언하십시오). 따라서 하나의 규칙 만 남겨 두겠습니다. 지시문에 상태가 있거나 사용되는 범위의 일부 데이터가 필요한 경우 격리 된 범위를 사용하십시오. 그렇지 않으면 범위를 사용하지 마십시오. 그리고 "자식 범위 (child scopes)"에 대해-나는 또한 많은 지시어를 작성했으며이 기능이 필요하지 않았습니다. "부모 범위에서 일부 요소를 변경해야하는 경우"-바인딩을 사용하십시오.
Valentyn Shybanov

또한 "부모 범위의 일부 요소를 변경해야합니다"에 대해-자식 범위의 항목을 수정하면 변경 내용이 상위 범위에 채워지지 않습니다 (더티 $parent해킹 을 사용하지 않는 한 ). 같은 - 그래서 지시어 실제로 "아이의 범위는"외모처럼 매우 리어를 사용하는 것을 무언가는 ngRepeat그 새 자식 반복 각 항목에 대한 스코프 생성 (그러나 또한 사용하여 생성 scope.$new();하지 scope: true.
Valentyn Shybanov

1
동일한 요소 내에서 여러 개의 격리 된 범위를 요청할 수 없으며 명시 적으로 바인딩하지 않으면 상위 범위의 함수에 액세스 할 수 없습니다. (권리 사용 ngClick등) 요청하면 동의하는 일종의 디커플링이 생성되지만 여전히 부모 지시 사항을 알아야합니다. 구성 요소 와 같지 않으면 격리를 반대합니다. 지시어 (적어도 대부분의 지시어)는 재사용 성이 높아야하며 격리가이를 중단시킵니다.
Umur Kontacı

또한 지시문에서 자식 범위를 사용하지 않지만 자식 범위는 부모 범위에서 프로토 타입으로 상속되므로 부모 범위의 속성에있는 속성에 대한 액세스 권한이 있으면 변경 내용이 채워집니다. 각도의 저자는 MTV의 만남에 대해 이야기, 그것은이다 "좋은 도트 어딘가에 갖고" youtube.com/watch?v=ZhfUv0spHCY
Umur Kontacı

5
첫째, 격리 범위가 너무 가혹하다고 생각합니다. 나는 그들이 당신이 가지고있는 것보다 더 넓은 적용 가능성을 가지고 있다고 생각하며 그것을 사용할 때 우리가 지적한 많은 도전을 피할 수있는 방법이 있다고 생각합니다. 또한 "최종 개발자를위한 많은 사용자 정의"에 동의하지 않습니다. 자세한 내용은 답변을 참조하십시오. 즉, 귀하의 답변은 나쁘지 않고 잘못이 아니며 질문을 해결 했으므로 왜 투표에 실패했는지 잘 모르겠습니다. +1입니다.
Josh David Miller

9

방금 내 이해와 다른 JS 개념과의 관련성을 추가한다고 생각했습니다.

기본값 (예 : 선언되지 않거나 범위 : false)

이것은 전역 변수를 사용하는 것과 철학적으로 동일합니다. 지시어는 상위 컨트롤러의 모든 것에 액세스 할 수 있지만 동시에 영향을 미치며 영향을받습니다.

범위:{}

이것은 모듈과 같으므로 사용하려는 모든 것이 명시 적으로 전달되어야합니다. 사용하는 모든 지시문이 격리 범위이면 모든 종속 파일을 주입하는 데 많은 오버 헤드가있는 자체 모듈을 작성하는 모든 JS 파일을 만드는 것과 같습니다.

범위 : 아이

이것이 전역 변수와 명시 적 통과 사이의 중간 지점입니다. 그것은 자바 스크립트의 프로토 타입 체인과 유사하며 부모 범위의 사본을 확장합니다. 분리 범위를 작성하고 상위 범위의 모든 속성과 기능을 전달하면 기능적으로 이것과 같습니다.


핵심은 모든 지시문은 어떤 방식 으로든 작성할 수 있다는 것입니다. 다른 범위 선언은 구성에 도움이됩니다. 모든 것을 모듈로 만들거나 모든 전역 변수를 사용하고 매우 조심할 수 있습니다. 유지 관리의 편의성을 위해 논리를 논리적으로 일관된 부분으로 모듈화하는 것이 바람직합니다. 열린 초원과 닫힌 감옥 사이에는 균형이 있습니다. 이것이 까다로운 이유는 사람들이 이것에 대해 배울 때 지시어의 작동 방식에 대해 배우고 있지만 실제로 코드 / 논리 조직에 대해 배우고 있다고 생각하기 때문입니다.

지시문이 어떻게 작동하는지 알아내는 데 도움이 된 또 다른 것은 ngInclude에 대해 배우고 있습니다. ngInclude는 HTML 부분을 포함하는 데 도움이됩니다. 지시문을 처음 사용하기 시작했을 때 템플릿 옵션을 사용하여 코드를 줄일 수는 있지만 실제로 논리를 첨부하지는 않았습니다.

물론 angular의 지시문과 angular-ui 팀 의 작업 사이에 나는 실질적인 것을 수행하는 내 지시문을 아직 만들지 않았으므로 이것에 대한 나의 견해가 완전히 잘못 될 수 있습니다.


2

나는 Umur와 동의합니다. 이론적으로 격리 된 스코프는 훌륭하고 "휴대용"으로 들리지만, 사소한 기능을 포함하도록 내 앱을 구축 할 때 내 전체를 완전히 작성하기 위해 여러 가지 지시문 (다른 일부에 중첩되거나 속성을 추가)을 통합 해야하는 필요성에 직면했습니다. 도메인 고유 언어의 목적인 자체 HTML.

결국, 격리 범위에 필요한대로 지시문의 각 DOM 호출에서 여러 속성으로 체인에 모든 전역 또는 공유 값을 전달해야하는 것은 너무 이상합니다. DOM에서 모든 것을 반복적으로 쓰는 것은 바보 같고 공유 객체 인 경우에도 비효율적이라고 느낍니다. 또한 지시문 선언을 불필요하게 복잡하게 만듭니다. 지시어 HTML에서 "도달"하고 값을 가져 오기 위해 $ parent를 사용하는 해결 방법은 매우 잘못된 형식 인 것 같습니다.

나도 아주 적은 수의 분리 물을 가진 대부분의 자식 범위 지시문을 갖도록 앱을 변경했습니다. 단순하고 반복되지 않는 속성을 통해 전달 될 수있는 것 이외의 부모로부터 모든 것에 액세스 할 필요가없는 지시자 만 있습니다.

그러한 일이 있기 전에 수십 년 동안 Domain Specific Languages의 꿈을 꿈꿔 왔던 AngularJS 가이 옵션을 제공 하고이 분야에서 더 많은 개발자가 작업함에 따라 우리는 매우 멋진 앱을 보게 될 것을 알고 있습니다 또한 건축가가 작성, 확장 및 디버깅하기가 쉽습니다.

-D

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.