문서가 준비된 AngularJS 컨트롤러에서 기능을 실행하는 방법은 무엇입니까?


254

각도 컨트롤러 내에 함수가 있습니다.이 함수를 문서 준비에서 실행하고 싶지만 dom이 생성 될 때 각도가 실행되는 것을 알았습니다.

 function myController($scope)
 {
     $scope.init = function()
     {
        // I'd like to run this on document ready
     }

     $scope.init(); // doesn't work, loads my init before the page has completely loaded
 }

아무도 내가 어떻게 할 수 있는지 알고 있습니까?

답변:


449

angular.element(document).ready()메소드를 사용하여 문서가 준비 될 때 콜백을 첨부 할 수 있습니다 . 다음과 같이 컨트롤러에 콜백을 간단히 연결할 수 있습니다.

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    angular.element(document).ready(function () {
        document.getElementById('msg').innerHTML = 'Hello';
    });
}]);

http://jsfiddle.net/jgentes/stwyvq38/1/


64
또는 $ document.ready (function () {...}), Angular Docs를 사용할 수 있습니다 : docs.angularjs.org/api/ng/service/$document
StuR

29
$document그것을 사용 하려면 주사해야 합니다. angular.element기본적으로 작동합니다.
nshew

17
사용하려면 $ document를 삽입해야하지만 document 요소를 참조하는 것이 좋습니다. 그럴 필요는 없지만 테스트가 더 쉬워집니다.
Jason Cox

10
document$document각도에 의해 주입 될 수 있는 전역 변수 이므로 테스트가 더 쉬워집니다. 일반적으로 문서 또는 창과 같은 전역 JS 변수에 액세스하는 응용 프로그램을 단위 테스트하기는 어렵습니다. 또한 module.run컨트롤러 대신이 코드를 넣을 수있는 좋은 장소 라고 생각합니다 .
lanoxx

7
이것은 나를 위해 작동하지 않습니다. getElementById 호출은 null을 반환합니다.
ThePartyTurtle

29

이 게시물 참조 페이지로드에서 각도 컨트롤러 기능을 실행하는 방법은 무엇입니까?
빠른 조회 :

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>

// in controller
$scope.init = function () {
    // check if there is query in url
    // and fire search in case its value is not empty
};

이렇게하면 문서가 준비 될 때까지 기다릴 필요가 없습니다.


1
후 페이지로드를 호출해야하는 경우 어떻게합니까?
Rishi

22

Angular는 DOMContentLoaded이벤트시 또는 angular.js 스크립트가 평가 될 때 document.readyState가 'complete'로 설정된 경우 자동으로 초기화됩니다 . 이 시점에서 Angular는 응용 프로그램 루트를 지정하는 ng-app 지시문을 찾습니다.

https://docs.angularjs.org/guide/bootstrap

이는 컨트롤러 코드가 DOM이 준비된 후에 실행됨을 의미합니다.

따라서 그것은 단지 $scope.init()입니다.


9
나는 그것을 시도했지만 이상하게도 내 페이지의 일부가로드되지 않았습니다.
foreyez

그리고 aotomated 웹 테스트를 작성할 때 버튼 클릭과 같은 작업을 수행하기 전에 각 코드가 언제 준비되었는지 알 수 있습니까?
akostadinov

또한 DOMContentLoaded스타일 시트, 이미지 및 서브 프레임이로드를 완료 할 때까지 기다리지 않고 문서가 완전히로드되고 파싱 될 때 시작됩니다. 자세한 정보 는 DOMContentLoaded와 load 이벤트의 차이점무엇입니까?를 참조하십시오 . .
georgeawg

22

Angular에는 함수 실행을 시작하는 몇 가지 시점이 있습니다. jQuery와 같은 것을 찾고 있다면

$(document).ready();

이 아날로그가 각도로 매우 유용하다는 것을 알 수 있습니다.

$scope.$watch('$viewContentLoaded', function(){
    //do something
});

DOM 요소를 조작 할 때 유용합니다. 모든 te 요소가로드 된 후에 만 ​​실행을 시작합니다.

UPD : 위의 내용은 CSS 속성을 변경하려고 할 때 작동합니다. 그러나 너비, 높이 등과 같은 요소 속성을 측정하려는 경우 때때로 작동하지 않습니다.이 경우 다음을 시도 할 수 있습니다.

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

이것은 제안 된 답변보다 더 가치가 있습니다. $ timeout을 사용하지 않고이 작업을 수행했습니다.
Richie86

그것은 setTimeout (0)으로 만 작동합니다. 예를 들어 ng-repeat 아래의 내용은 아직로드되지 않았습니다.
Ignacio Vazquez

2

뷰가로드 된 후와 뷰 내의 특정 타사 구성 요소가로드되고 초기화 된 후 $ scope에서 자체에 대한 참조를 지정한 후에 컨트롤러 기능을 실행 해야하는 비슷한 상황이있었습니다. 나를 위해 일한 것은이 스코프 속성에 시계를 설정하고 초기화 된 후에 만 ​​기능을 시작하는 것이 었습니다.

// $scope.myGrid property will be created by the grid itself
// The grid will have a loadedRows property once initialized

$scope.$watch('myGrid', function(newValue, oldValue) {
    if (newValue && newValue.loadedRows && !oldValue) {
        initializeAllTheGridThings();
    }
});

감시자는 정의되지 않은 값으로 몇 번 호출됩니다. 그런 다음 그리드가 만들어지고 예상 속성이 있으면 초기화 함수가 안전하게 호출 될 수 있습니다. 정의되지 않은 newValue로 감시자가 처음 호출 될 때 oldValue는 여전히 정의되지 않습니다.


1

다음은 coffeescript를 사용하는 외부 컨트롤러 내부의 시도입니다. 오히려 잘 작동합니다. settings.screen.xs | sm | md | lg는 앱에 포함 된 미 확대 파일에 정의 된 정적 값입니다. 값은 시사 미디어 쿼리 크기에 대한 Bootstrap 3 공식 중단 점에 따라 다릅니다.

xs = settings.screen.xs // 480
sm = settings.screen.sm // 768
md = settings.screen.md // 992
lg = settings.screen.lg // 1200

doMediaQuery = () ->

    w = angular.element($window).width()

    $scope.xs = w < sm
    $scope.sm = w >= sm and w < md
    $scope.md = w >= md and w < lg
    $scope.lg = w >= lg
    $scope.media =  if $scope.xs 
                        "xs" 
                    else if $scope.sm
                        "sm"
                    else if $scope.md 
                        "md"
                    else 
                        "lg"

$document.ready () -> doMediaQuery()
angular.element($window).bind 'resize', () -> doMediaQuery()

1

대답

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

내가 테스트 한 대부분의 시나리오에서 작동하는 유일한 것입니다. 템플릿에서 HTML을 빌드하는 4 가지 구성 요소가 포함 된 샘플 페이지에서 이벤트 순서는 다음과 같습니다.

$document ready
$onInit
$postLink
(and these 3 were repeated 3 more times in the same order for the other 3 components)
$viewContentLoaded (repeated 3 more times)
$timeout execution (repeated 3 more times)

따라서 $ document.ready ()는 대부분의 경우 쓸모가 없습니다. 각도로 생성되는 DOM은 거의 준비가되어 있지 않기 때문입니다.

그러나 더 흥미로운 것은 $ viewContentLoaded가 실행 된 후에도 여전히 관심있는 요소를 찾을 수 없었습니다.

$ timeout이 실행 된 후에 만 ​​발견되었습니다. $ timeout의 값이 0 이었지만 실행되기 전에 거의 200 밀리 초가 걸렸으며이 스레드가 꽤 오랫동안 보류되어 있음을 나타냅니다. DOM에는 기본 스레드에 각도 템플릿이 추가 된 것 같습니다. 첫 $ document.ready ()에서 마지막 $ timeout 실행까지의 총 시간은 거의 500 밀리 초였습니다.

구성 요소 값이 설정되고 $ timeout에서 나중에 text () 값이 변경된 특별한 경우 $ timeout 값은 $ timeout 동안 요소를 찾을 수 있었지만 작동 할 때까지 증가해야했습니다. ). 타사 구성 요소 내에서 비동기로 인해 충분한 시간이 지날 때까지 텍스트보다 값이 우선합니다. 다른 가능성은 $ scope. $ evalAsync이지만 시도되지 않았습니다.

나는 여전히 DOM이 완전히 해결되었고 모든 사례가 작동하도록 조작 할 수 있다고 말하는 하나의 이벤트를 찾고 있습니다. 지금까지 임의의 시간 초과 값이 필요합니다. 기껏해야 이것이 느린 브라우저에서 작동하지 않는 kludge임을 의미합니다. 나는 작동 할 수있는 liveQuery 및 publish / subscribe와 같은 JQuery 옵션을 시도하지 않았지만 반드시 순수한 각도는 아닙니다.


1

와 같은 것을 얻는다면 getElementById call returns null아마도 함수가 실행 중일 수 있지만 ID가 DOM에로드 할 시간이 없었기 때문일 수 있습니다.

Will 's answer (위쪽으로)를 늦게 사용해보십시오. 예:

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    $scope.sleep = (time) => {
        return new Promise((resolve) => setTimeout(resolve, time));
    };
    angular.element(document).ready(function () {
        $scope.sleep(500).then(() => {        
            //code to run here after the delay
        });
    });
}]);

0

앵귤러 문서에서 https://docs.angularjs.org/api/ng/function/angular.element에 대해 언급 해보십시오 .

angular.element (콜백)

$ onInit () {...} 함수 내에서 이것을 사용했습니다.

 var self = this;

 angular.element(function () {
        var target = document.getElementsByClassName('unitSortingModule');
        target[0].addEventListener("touchstart", self.touchHandler, false);
        ...
    });

이것은 나를 위해 일했습니다.


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