$postLink 각진 컴포넌트/방향성이 너무 빨리 실행됨
업데이트: 나는 이 질문에 현상금을 걸었다.나는 해킹이나 회피책을 찾고 있지 않다.각진 컴포넌트에서 돔에 액세스하기 위한 공식적인 방법을 찾고 있는데, 왜 ("postLink running to early") 동작이 공식 문서와 모순되는지를 설명합니다.
공식 문서는 다음과 같습니다.
$postLink() - 이 컨트롤러의 요소와 그 자 요소가 링크된 후에 호출됩니다.링크 후 기능과 마찬가지로 이 후크는 DOM 이벤트 핸들러를 설정하고 직접 DOM 조작을 수행하는 데 사용할 수 있습니다.
첫 번째 질문:여기 문제의 예가 있습니다.-> http://plnkr.co/edit/rMm9FOwImFRziNG4o0sg?p=preview
앵글 컴포넌트를 사용하고 있는데 포스트 링크 기능으로 돔을 수정하고 싶은데, 기능이 너무 빨리 실행되어 템플릿이 실제로 돔에서 준비되기 전에 앵글 처리를 모두 완료했습니다.
html 페이지에는 다음과 같은 내용이 있습니다.
<my-grid grid-id="'foo'"></my-grid>
컴포넌트는 다음과 같이 정의됩니다.
appModule.component('myGrid',{
controller: gridController,
bindings: {
"gridId": "<",
},
templateUrl: 'gridTemplate'
});
컴포넌트 템플릿에는 다음과 같은 것이 있습니다.
<table id='{{$ctrl.gridId}}'>
...
(바인딩 자체는 확실히 효과가 있습니다.최종적으로 html에서 테이블의 ID는 예상대로 'foo'가 됩니다).
컨트롤러에는 다음과 같은 기능이 있습니다.
function gridController($scope, $compile, $attrs) {
console.log ("grid id is: " + this.gridId); // 'foo'
this.$postLink = function() {
var elem = document.getElementById(this.gridId);
// do something with elem, but elem is null
}
}
시 때돔 $postLink입니다.{{$ctrl.gridId}}
foo
, (그래서)document.getElementById()
이치노이치노
가가무 엇뜨 ?뜨? ???컴포넌트의 돔에 접근하는 다른 방법이 있나요?
업데이트 2: 오늘 저는 디렉티브의 일반 링크 기능에서도 동일한 문제가 발생한다는 것을 알았습니다.이것은 컴포넌트에 한정되지 않습니다.direct DOM 조작의 의미를 잘못 이해한 것 같습니다.- 링크 함수는 돔에서 분리된 요소에서 실행되기 때문에 do direct DOM 조작을 사용합니다.document
이치노
『 』에 관한 $postLink()
그 되어 있다고 이에요.컨트롤러의 요소와 하위 요소가 연결된 후 호출됩니다.이것은 지시어의 결과를 즉시 볼 수 있다는 것을 의미하지 않습니다.'아예'를 부르고 있을 예요.$http
결과가 도착하면 삽입하는 거죠.아마도 Angular의 기본 제공 디렉티브가 그러하듯이 결과를 설정하는 감시자를 등록하는 것일 수도 있습니다.
이 경우 근본적인 문제는 보간 컴파일 후 또는 등록된 워처가 한 번 실행한 후 DOM 조작을 수행하려는 것입니다.
유감스럽게도, 이것을 할 수 있는 공식적인 방법은 없습니다.그러나 이를 실현하는 방법은 여러 가지가 있지만 매뉴얼에는 기재되어 있지 않습니다.
보간 컴파일 후 함수를 실행하는 두 가지 일반적인 방법은 다음과 같습니다.
를 사용합니다.
$timeout
이므로): "0" (0) :$timeout(function() { /* Your code goes here */ });
를 사용합니다.
.ready()
Angular의 jqLite에 의해 제공됩니다.
이 경우 주어진 ID를 가진 요소가 존재하면 워처를 사용하여 함수를 실행하는 것이 훨씬 좋습니다.
var deregistrationFn = $scope.$watch(() => {
return document.getElementById(this.gridId);
}, (newValue) => {
if (newValue !== null) {
deregistrationFn();
// Your code goes here
}
});
마지막으로, 내 생각에, 당신이 보간법이 작성되기를 기다리거나 그 가치를 삽입하기 위해 특정한 지시를 기다릴 필요가 있을 때마다 당신은 앵글의 건축 방식을 따르지 않는 것 같아요.당신의 경우, 새로운 컴포넌트를 작성하면 어떨까요?myGridTable
, 「」가 필요합니다.myGrid
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★이렇게 하면 각 컴포넌트의 책임이 훨씬 명확하게 정의되어 테스트하기가 쉬워집니다.
각 $digest 사이클이 컨트롤러 라이프 사이클 이벤트(및 지시 라이프 사이클 이벤트)와 어떻게 연동되는지에 대한 오해입니다.
컨트롤러/다이렉트 라이프 사이클 이벤트는 각각 $apply 내에서 호출됩니다.따라서 DOM은 $digest 사이클이 완료된 후에만 변경 내용을 반영하도록 업데이트됩니다.
포스트 링크 함수는 모든 것이 링크된 후에 실행되지만 $digest 사이클 내에서 실행되는 마지막 함수이기 때문에 모든 바인딩을 반영하도록 이 함수의 마지막에 DOM이 업데이트됩니다.즉, 바인딩의 영향을 받는 것에 대해 DOM을 쿼리하려고 해도 동작하지 않습니다(예:ng-repeat
」를 참조해 주세요.다만, docs 스테이트에서는, DOM 의 링크는 이미 실행되고 있기 때문에, 초기 템플릿이 작성되어 조작할 수 있습니다.
바인딩을 적용한 후 DOM을 조회해야 하므로 현재 $digest 사이클이 완료된 후 코드를 실행해야 합니다., '나', '나'를 사용한다는 뜻입니다.$timeout
지연이 0인 경우 현재 $120 사이클이 종료된 직후 실행됩니다.
function gridController($scope, $compile, $attrs, $timeout) {
console.log ("grid id is: " + this.gridId); // 'foo'
this.$postLink = function() {
$timeout(function() {
var elem = document.getElementById(this.gridId);
// do something with elem now that the DOM has had it's bindings applied
});
}
}
이는 해결책을 제시하기 전에 각 구성 요소 시나리오를 이해하는 것과 관련이 있는 것으로 보인다.그리고 이 예에서 분리된 스코프에 로드된 템플릿 DOM을 볼 수 있습니다.격리된 범위 반복
그렇게,
컴포넌트에 관한 공식 문서 [1.5.6]에 따르면 https://docs.angularjs.org/guide/component
컴포넌트를 사용하지 않는 경우:
- DOM 조작, 이벤트 청취자 추가 등에 의존하는 지시의 경우, 컴파일 및 링크 기능을 사용할 수 없기 때문에
- priority, terminal, multi-time 등의 고급 디렉티브 정의 옵션이 필요한 경우
- 요소가 아닌 Atribut 또는 CSS 클래스에 의해 트리거되는 디렉티브가 필요한 경우
문서의 "Directive 정의와 Component 정의 비교" 섹션을 볼 수 있습니다.
- feature-----------------------------------------------
- 바인딩 -----------------------------------------------------------------------------------------------------------
- bindToController---Yes(기본값: false)-No(바인딩 대신 사용)
- 컴파일 함수 -------------------------------------------------------------
- controller-------------------------------------------------------------------------------------------
- controllerAs------------------------------------------------------------------------------------------------------------------
- 링크 함수 --------------------------------------------------------------------
지금이다
컴포넌트는 자신의 범위를 벗어나는 데이터 또는 DOM을 수정해서는 안 됩니다.일반적으로 Angular에서는 스코프 상속 및 워치를 통해 애플리케이션 내 어디서나 데이터를 수정할 수 있습니다.이것은 실용적이지만, 애플리케이션의 어느 부분이 데이터를 수정하는지가 명확하지 않은 경우에도 문제가 발생할 수 있습니다.그렇기 때문에 컴포넌트 디렉티브는 격리된 스코프를 사용하기 때문에 모든 클래스의 스코프를 조작할 수 없습니다.참조: ng-doc 1.5.6
하지만 $postLink() 훅이라는 광고를 보면 그 이유가 무엇인지 궁금할 수 있습니다.
단, 이 훅에 대한 설명을 확인하시면...
templateUrl 디렉티브를 포함하는 자녀 요소는 템플릿이 비동기적으로 로드되기를 기다리고 있으며 그 때까지 자체 컴파일 및 링크가 일시 중단되므로 컴파일 및 링크되지 않습니다.
아래의 Steven Lambert 답변을 참조하십시오.
언급URL : https://stackoverflow.com/questions/37146700/postlink-of-an-angular-component-directive-running-too-early
'programing' 카테고리의 다른 글
org.springframework.boot.web.support가 존재하지 않습니다. (0) | 2023.03.14 |
---|---|
폐지 통지:React DOM.render는 React 18에서 지원되지 않습니다. (0) | 2023.03.14 |
속성별 배열 정렬 (0) | 2023.03.14 |
트리거 $document.ready(수정할 수 없는 AJAX 코드가 실행됨) (0) | 2023.03.09 |
Angular.js는 이전 방식으로 제출합니다. (0) | 2023.03.09 |