itsource

Angular가 DOM에 스코프 업데이트를 추가한 후 메서드를 트리거하는 방법은 무엇입니까?

mycopycode 2023. 2. 26. 09:43
반응형

Angular가 DOM에 스코프 업데이트를 추가한 후 메서드를 트리거하는 방법은 무엇입니까?

$scope 변수에 변경을 추가한 후 코드를 실행하는 방법을 찾고 있습니다.이 경우 $scope.results입니다.실행되기 전에 항목이 DOM에 있어야 하는 레거시 코드를 호출하려면 이 작업을 수행해야 합니다.

실제 코드는 AJAX 호출을 트리거하고 스코프 변수를 업데이트하여 UI를 업데이트하는 것입니다.따라서 스코프로 푸시한 직후에 코드가 실행되고 있습니다만, 아직 dom 요소를 사용할 수 없기 때문에 레거시 코드가 실패합니다.

set Timeout()을 사용하여 추악한 지연을 추가할 수 있지만, 그렇다고 해서 DOM이 제대로 준비되는 것은 아닙니다.

제 질문은, 제가 '렌더드'와 같은 이벤트에 얽매일 수 있는 방법이 있을까요?

var myApp = angular.module('myApp', []);

myApp.controller("myController", ['$scope', function($scope){
    var resultsToLoad = [{id: 1, name: "one"},{id: 2, name: "two"},{id: 3, name: "three"}];
    $scope.results = [];

    $scope.loadResults = function(){
        for(var i=0; i < resultsToLoad.length; i++){
            $scope.results.push(resultsToLoad[i]);
        }
    }

    function doneAddingToDom(){
        // do something awesome like trigger a service call to log
    }
}]);
angular.bootstrap(document, ['myApp']);

시뮬레이션 코드 링크: http://jsfiddle.net/acolchado/BhApF/5/

잘 부탁드립니다!

$evalAsync 큐는 현재 스택프레임 외부에서 브라우저 뷰 렌더 전에 발생할 필요가 있는 작업을 스케줄링하기 위해 사용됩니다.http://docs.angularjs.org/guide/concepts#runtime

그럼 '스택 프레임'이 뭐죠?Github 코멘트는 다음과 같은 내용을 나타냅니다.

컨트롤러에서 큐잉하는 경우는 이전이지만 디렉티브에서 큐잉하는 경우는 이후가 됩니다.https://github.com/angular/angular.js/issues/734#issuecomment-3675158

위에서 Misko는 DOM이 Angular에 의해 갱신되었을 때와 관련하여 $evalAsync에 의해 실행 큐잉된 코드가 언제 실행되는지 논의하고 있습니다.그 전에 두 개의 Github 코멘트를 읽고 전체적인 맥락을 파악할 것을 제안합니다.

따라서 디렉티브에서 $evalAsync를 사용하여 코드를 큐잉할 경우 DOM이 Angular에 의해 조작된 후 브라우저가 렌더링하기 전에 실행해야 합니다.브라우저 렌더링 후 또는 컨트롤러가 모델을 업데이트한 후 무언가를 실행해야 하는 경우$timeout(..., 0);

$evalAsync()를 사용하는 예제 바이올린도 있는 https://stackoverflow.com/a/13619324/215945,을 참조하십시오.

내가 네 바이올린을 갈랐다.http://jsfiddle.net/xGCmp/7/

emiss-when이라는 명령을 추가했습니다.두 가지 파라미터가 필요합니다.방출되는 이벤트와 방출되는 이벤트를 위해 충족해야 하는 조건.이것은 링크 함수가 디렉티브로 실행되었을 때 요소가 DOM에 렌더링된 것을 알 수 있기 때문에 동작합니다.저의 해결책은 ng-repeat의 마지막 항목이 렌더링되었을 때 이벤트를 내보내는 것입니다.

만약 All Angular 솔루션이 있다면, 저는 이것을 추천하지 않습니다.좀 허술한 것 같아요.단, 말씀하신 레거시코드의 유형을 처리하는 데 적합한 솔루션이 될 수 있습니다.

var myApp = angular.module('myApp', []);

myApp.controller("myController", ['$scope', function($scope){
    var resultsToLoad = [
        {id: 1, name: "one"},
        {id: 2, name: "two"},
        {id: 3, name: "three"}
    ];

    function doneAddingToDom() {
        console.log(document.getElementById('renderedList').children.length);
    }

    $scope.results = [];

    $scope.loadResults = function(){
        $scope.results = resultsToLoad;
        // If run doneAddingToDom here, we will find 0 list elements in the DOM. Check console.
        doneAddingToDom();
    }

    // If we run on doneAddingToDom here, we will find 3 list elements in the DOM.
    $scope.$on('allRendered', doneAddingToDom);
}]);

myApp.directive("emitWhen", function(){
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var params = scope.$eval(attrs.emitWhen),
                event = params.event,
                condition = params.condition;
            if(condition){
                scope.$emit(event);
            }
        }
    }
});

angular.bootstrap(document, ['myApp']);

타임아웃을 사용하는 것은 올바른 방법이 아닙니다.지시어를 사용하여 DOM을 추가/조작합니다.timeout을 사용하는 경우 반드시 Angular에 연결된 $timeout을 사용하십시오(예: 약속 반환).

저와 같은 경우, 대부분의 경우 DOM이 완전히 안정되고 완전히 정적이 되기 전에 $timeout이 0으로 실행된다는 것을 알 수 있습니다.DOM이 안정되고 싶을 때는 안정되고 싶다.여기서 발견한 솔루션은 "DOMSubtreeModified" 이벤트를 위해 요소(또는 문서 전체의 예시와 같이)에 워처를 설정하는 것입니다.500밀리초를 기다려도 DOM에 변화가 없으면 "Domendered"와 같은 이벤트를 브로드캐스트합니다.

IE:

   //todo: Inject $rootScope and $window, 


   //Every call to $window.setTimeout will use this function
   var broadcast = function () {};

   if (document.addEventListener) {

       document.addEventListener("DOMSubtreeModified", function (e) {
           //If less than 500 milliseconds have passed, the previous broadcast will be cleared. 
           clearTimeout(broadcast)
           broadcast = $window.setTimeout(function () {
               //This will only fire after 500 ms have passed with no changes
               $rootScope.$broadcast('domRendered')
           }, 500)

       });

   //IE stupidity
   } else {
       document.attachEvent("DOMSubtreeModified", function (e) {

           clearTimeout(broadcast)
           broadcast = $window.setTimeout(function () {
               $rootScope.$broadcast('domRendered')
           }, 500)

       });
   }

이 이벤트는 모든 브로드캐스트와 마찬가지로 다음과 같이 접속할 수 있습니다.

$rootScope.$on("domRendered", function(){
   //do something
})

했습니다.height()의 of의 element가 정해진 의 내 안에.$digest브라우저가 레이아웃을 흘려보냈습니다.

서서 link; 명령어

이 방법은 신뢰성도 없고, 거의 늦지 않았습니다.

scope.$watch(function() {}); 

아직 충분히 늦지는 않았다.

scope.$evalAsync(function() {});

크롬 과 같은 이 작동하는 것 .ẁindow.setTimeout()scope.$apply() 않았다 하지 않았다.

$timeout(function() {}, 0);

하지만 플리커가 걱정돼서 결국엔 이 제품을 사용했어요.requestAnimationFrame()$timeout 말하면심플하게 말하면, 이것은 기본적으로 다음과 같습니다.

scope.$watch("someBoundPropertyIexpectWillAlterLayout", function(n,o) {
    $window.requestAnimationFrame(function() {
        scope.$apply(function() {
            scope.height = element.height(); // OK, this seems to be accurate for the layout
        });
    });
});

그럼 당연히 a를 사용할 수 있습니다.

scope.$watch("height", function() {
    // Adjust view model based on new layout metrics
});

interval은 다음과 같이 기능합니다.

interval = $interval(function() {
    if ($("#target").children().length === 0) {
        return;
    }
    doSomething();
    $interval.cancel(interval);
}, 0);

언급URL : https://stackoverflow.com/questions/17225106/how-to-trigger-a-method-when-angular-is-done-adding-scope-updates-to-the-dom

반응형