programing

$postLink 각진 컴포넌트/방향성이 너무 빨리 실행됨

powerit 2023. 3. 14. 21:56
반응형

$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

반응형