AngularJS가 로딩을 마치면 이벤트 보내기
모든 지시어가 완료 / 링크를 완료했을 때 페이지 로딩 / 부팅 완료를 감지하는 가장 좋은 방법이 무엇인지 궁금했습니다.
이미 이벤트가 있습니까? 부트 기능을 추가해야합니까?
직감 : ngCloak 지시어가 어떻게 작동하는지 보지 보장겠습니까? 분명히 ngCloak 지시문은 내용이로드 된 후 내용을 표시하도록 관리합니다. ngCloak을 보면 정확한 답변을받을 수 있습니다 ...
1 시간 후 수정 : 좋아, ngCloak 를 누르 는데 정말 짧습니다. 이것이 암시하는 것은 {{template}} 즉,로드 된 템플릿이 실행되지 않는 것입니다.
저의 교육받은 추측은 ngCloak과 동일한 단순성을 가진 지시문을 만든 다음 함수에서 원하는 것을 수행하는 것입니다. :) 지시문을 앱의 루트 요소에 배치하십시오. myOnload와 같은 지시문을 호출하여 my-onload 속성으로 사용할 수 있습니다. (표현식과 하위 템플릿이로드 됨).
23 시간 후 수정 : 좋아, 조사를 해보았 고 나 자신도 질문을했다 . 내가 묻는 질문은이 질문과 간접적으로 관련이 있었지만 우연히이 질문을 해결하는 답변으로 연결됩니다.
답은 간단한 지시어를 만들고 지시어의 링크 함수에 코드를 넣을 수있는 것입니다.이 함수는 (대부분의 경우 아래에서 설명) 요소가 /로드 될 때 실행됩니다. 컴파일 및 링크 함수가 실행되는 순서 에 대한 조쉬 설명을의 -based으로 ,
이 마크 업이있는 경우 :
<div directive1> <div directive2> <!-- ... --> </div> </div>
그런 다음 AngularJS는 지시문 함수를 특정 순서로 실행하여 지시문을 작성합니다.
directive1: compile directive2: compile directive1: controller directive1: pre-link directive2: controller directive2: pre-link directive2: post-link directive1: post-link
기본적으로 직선적 인 "링크"기능은 사후 링크 내부 지시어 2의 링크 함수가 실행될 것이라는 지시어 1의 링크 함수가 실행되지 않습니다. 그래서 우리는 포스트 링크에서 DOM 조작을하는 것이 안전하다는 것입니다. 따라서 원래 질문에있는 외부 지시문의 링크 함수에서 지시하는 데 문의 내부 HTML에 액세스하는 데 문의 내부 HTML에 액세스하는 문제가 없어야하지만 언급 된 내용을 동적으로 삽입해야합니다.
이것으로 우리는 모든 것이 준비를 / 링크 /로드 될 때 코드를 실행하기위한 지시어를 만들 수 있습니다.
app.directive('ngElementReady', [function() {
return {
priority: -1000, // a low number so this directive loads after all other directives have loaded.
restrict: "A", // attribute only
link: function($scope, $element, $attributes) {
console.log(" -- Element ready!");
// do what you want here.
}
};
}]);
이제 할 수있는 일은 ngElementReady 지시문을 앱의 루트 요소에있는 console.log
로드하면 실행됩니다.
<body data-ng-app="MyApp" data-ng-element-ready="">
...
...
</body>
그렇게 간단합니다! 간단한 지시어를 작성하십시오. ;)
을 추가 표현식 $scope.$eval($attributes.ngElementReady);
하여 표현식 (예 : 함수)을 실행할 수 있도록 추가로 사용자 정의 할 수 있습니다 .
app.directive('ngElementReady', [function() {
return {
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
restrict: "A",
link: function($scope, $element, $attributes) {
$scope.$eval($attributes.ngElementReady); // execute the expression in the attribute.
}
};
}]);
그런 다음 모든 요소에서 사용할 수 있습니다.
<body data-ng-app="MyApp" data-ng-controller="BodyCtrl" data-ng-element-ready="bodyIsReady()">
...
<div data-ng-element-ready="divIsReady()">...<div>
</body>
요소가있는 범위 (컨트롤러에서)에 함수 (예 : bodyIsReady 및 divIsReady)가 정의되어 있는지 확인하십시오.
경고 : 나는 대부분 의 경우 에 효과가 있습니다. ngRepeat 및 ngIf와 같은 특정 지시문을 사용할 수 있습니다. 귀하의 지시는 발사하지 않을 수 있습니다. 예를 들어 ngIf가있는 요소에 새 ngElementReady 지시문을 포함 ngIf의 조건이 false로 평가 될 경우 ngElementReady 지시문이로드되지 않습니다. 예를 들어 ngInclude 지시문이있는 요소에 새 ngElementReady 지시문을 추가하면 ngInclude의 템플릿이 지시문이로드되지 않은 것입니다. 지시문을 모두 같은 요소에 배치하는 대신 지시문을 중첩 시켜서 지시문을 모두 같은 요소에 배치 할 수 있습니다. 예를 들어, 이렇게하면
<div data-ng-element-ready="divIsReady()">
<div data-ng-include="non-existent-template.html"></div>
<div>
이 대신에 :
<div data-ng-element-ready="divIsReady()" data-ng-include="non-existent-template.html"></div>
ngElementReady 지시문은 후자의 예제에서 언어 링크 기능은 실행되지 않습니다. 참고 : 지시문은 항상 사용되는 함수 위와 같은 시나리오에 따라 링크가 항상 실행되는 것은 아닙니다.
몇 분 후 수정 :
아, 그리고 질문에 완전히 대답하기 위해 , 속성 에서 실행되는 표현식이나 함수에서 지금 $emit
또는 $broadcast
이벤트를 할 수 있습니다 ng-element-ready
. :) 예 :
<div data-ng-element-ready="$emit('someEvent')">
...
<div>
몇 분 후에 편집하십시오.
@satchmorun의 답변도 작동하지만 초기로드 작동합니다. 다음 은 링크 함수 등을 포함하여 실행되는 순서를 설명 하는 매우 유용한 SO 질문 입니다 app.run
. 사용 사례에 따라 app.run
좋을 수도 있습니다.
5 개월 후 편집, 10 월 17 일 8:11 PST :
작동하지 않습니다. (예 : 콘텐츠의 최종 시점 설정을 각 부분 유지 추적으로 한 후 이벤트를 발생시키는 부분 범위가로드 된 작업을 수행하는 방법) 모든 부기 부분에 부기를 추가해야합니다. 부분이로드 된 후 수행).
10 월 23 일 오후 10시 52 분 PST 수정 :
이미지가로드 될 때 일부 코드를 실행하기위한 간단한 지시문을 만들었습니다.
/*
* This img directive makes it so that if you put a loaded="" attribute on any
* img element in your app, the expression of that attribute will be evaluated
* after the images has finished loading. Use this to, for example, remove
* loading animations after images have finished loading.
*/
app.directive('img', function() {
return {
restrict: 'E',
link: function($scope, $element, $attributes) {
$element.bind('load', function() {
if ($attributes.loaded) {
$scope.$eval($attributes.loaded);
}
});
}
};
});
10 월 24 일 오전 12:48에 PST 수정 :
원래 ngElementReady
지시문을 개선 하고로 이름을 변경했습니다 whenReady
.
/*
* The whenReady directive allows you to execute the content of a when-ready
* attribute after the element is ready (i.e. done loading all sub directives and DOM
* content except for things that load asynchronously like partials and images).
*
* Execute multiple expressions by delimiting them with a semi-colon. If there
* is more than one expression, and the last expression evaluates to true, then
* all expressions prior will be evaluated after all text nodes in the element
* have been interpolated (i.e. {{placeholders}} replaced with actual values).
*
* Caveats: if other directives exists on the same element as this directive
* and destroy the element thus preventing other directives from loading, using
* this directive won't work. The optimal way to use this is to put this
* directive on an outer element.
*/
app.directive('whenReady', ['$interpolate', function($interpolate) {
return {
restrict: 'A',
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
link: function($scope, $element, $attributes) {
var expressions = $attributes.whenReady.split(';');
var waitForInterpolation = false;
function evalExpressions(expressions) {
expressions.forEach(function(expression) {
$scope.$eval(expression);
});
}
if ($attributes.whenReady.trim().length == 0) { return; }
if (expressions.length > 1) {
if ($scope.$eval(expressions.pop())) {
waitForInterpolation = true;
}
}
if (waitForInterpolation) {
requestAnimationFrame(function checkIfInterpolated() {
if ($element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
requestAnimationFrame(checkIfInterpolated);
}
else {
evalExpressions(expressions);
}
});
}
else {
evalExpressions(expressions);
}
}
}
}]);
예를 들어, someFunction
요소가로드 {{placeholders}}
되었지만 아직 교체되지 않은 경우 이를 실행하려면 다음과 같이 사용하십시오 .
<div when-ready="someFunction()">
<span ng-repeat="item in items">{{item.property}}</span>
</div>
someFunction
모든 item.property
자리 표시자가 교체 되기 전에 호출 됩니다.
원하는만큼 식을 평가하고 마지막식이 다음과 같이 평가 될 true
때까지 기다리십시오 {{placeholders}}
.
<div when-ready="someFunction(); anotherFunction(); true">
<span ng-repeat="item in items">{{item.property}}</span>
</div>
someFunction
그리고 anotherFunction
이후에 발사 {{placeholders}}
될 것입니다.
나중에 나중에 변경 될 때가 아니라 처음로드 될 때만 작동합니다. $digest
-display자가보기 처음 자리 교체 된 후에도 계속 유지 되는 경우 원하는대로 작동하지 않을 수 있습니다 (데이터가 변경되지 않을 때까지 $ 다이제스트는 최대 10 번 발생할 수 있음). 적용됩니다.
10 월 31 일 오후 7시 26 분 PST 수정 :
아마 이것은 아마도 마지막이자 마지막 업데이트 일 것입니다. 이것은 아마도 유스 케이스 99.999에서 작동 할 것입니다 :
/*
* The whenReady directive allows you to execute the content of a when-ready
* attribute after the element is ready (i.e. when it's done loading all sub directives and DOM
* content). See: https://stackoverflow.com/questions/14968690/sending-event-when-angular-js-finished-loading
*
* Execute multiple expressions in the when-ready attribute by delimiting them
* with a semi-colon. when-ready="doThis(); doThat()"
*
* Optional: If the value of a wait-for-interpolation attribute on the
* element evaluates to true, then the expressions in when-ready will be
* evaluated after all text nodes in the element have been interpolated (i.e.
* {{placeholders}} have been replaced with actual values).
*
* Optional: Use a ready-check attribute to write an expression that
* specifies what condition is true at any given moment in time when the
* element is ready. The expression will be evaluated repeatedly until the
* condition is finally true. The expression is executed with
* requestAnimationFrame so that it fires at a moment when it is least likely
* to block rendering of the page.
*
* If wait-for-interpolation and ready-check are both supplied, then the
* when-ready expressions will fire after interpolation is done *and* after
* the ready-check condition evaluates to true.
*
* Caveats: if other directives exists on the same element as this directive
* and destroy the element thus preventing other directives from loading, using
* this directive won't work. The optimal way to use this is to put this
* directive on an outer element.
*/
app.directive('whenReady', ['$interpolate', function($interpolate) {
return {
restrict: 'A',
priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
link: function($scope, $element, $attributes) {
var expressions = $attributes.whenReady.split(';');
var waitForInterpolation = false;
var hasReadyCheckExpression = false;
function evalExpressions(expressions) {
expressions.forEach(function(expression) {
$scope.$eval(expression);
});
}
if ($attributes.whenReady.trim().length === 0) { return; }
if ($attributes.waitForInterpolation && $scope.$eval($attributes.waitForInterpolation)) {
waitForInterpolation = true;
}
if ($attributes.readyCheck) {
hasReadyCheckExpression = true;
}
if (waitForInterpolation || hasReadyCheckExpression) {
requestAnimationFrame(function checkIfReady() {
var isInterpolated = false;
var isReadyCheckTrue = false;
if (waitForInterpolation && $element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
isInterpolated = false;
}
else {
isInterpolated = true;
}
if (hasReadyCheckExpression && !$scope.$eval($attributes.readyCheck)) { // if the ready check expression returns false
isReadyCheckTrue = false;
}
else {
isReadyCheckTrue = true;
}
if (isInterpolated && isReadyCheckTrue) { evalExpressions(expressions); }
else { requestAnimationFrame(checkIfReady); }
});
}
else {
evalExpressions(expressions);
}
}
};
}]);
이렇게 사용하세요
<div when-ready="isReady()" ready-check="checkIfReady()" wait-for-interpolation="true">
isReady will fire when this {{placeholder}} has been evaluated
and when checkIfReady finally returns true. checkIfReady might
contain code like `$('.some-element').length`.
</div>
물론, 아마도 최적화 될 수 있습니다. requestAnimationFrame 이 좋습니다.
에 대한 문서angular.Module
에는 run
함수를 설명하는 항목이 있습니다.
인젝터가 모든 모듈의 로딩을 완료했을 때 수행해야하는 작업을 등록해야합니다.
따라서 앱 인 모듈이있는 경우 :
var app = angular.module('app', [/* module dependencies */]);
모듈이 다음과 같이로드 된 후에 작업을 사용할 수 있습니다.
app.run(function() {
// Do post-load initialization stuff here
});
편집 : 구조에 수동 초기화
따라서 run
DOM이 준비되어 링크 될 때 처리 되지 않습니다 . 에 $injector
의해 참조 된 모듈에, 대한 ng-app
모든 종속성을로드 할 때 호출 되며 , 이는 DOM 컴파일 단계와 별개입니다.
수동 초기화에 대해 다시 논의합니다.
HTML은 간단합니다 :
<html>
<body>
<test-directive>This is a test</test-directive>
</body>
</html>
의 부족에 주목하십시오 ng-app
. 그리고 DOM 조작을하는 지시어가 있으므로 순서와 시간을 확인할 수 있습니다.
스케이트와 같이 모듈이 생성됩니다.
var app = angular.module('app', []);
지시어는 다음과 가변합니다.
app.directive('testDirective', function() {
return {
restrict: 'E',
template: '<div class="test-directive"><h1><div ng-transclude></div></h1></div>',
replace: true,
transclude: true,
compile: function() {
console.log("Compiling test-directive");
return {
pre: function() { console.log("Prelink"); },
post: function() { console.log("Postlink"); }
};
}
};
});
test-directive
태그를 div
클래스 로 바꾸고 test-directive
그 내용을로 묶습니다 h1
.
사전 및 사후 링크 기능을 모두 제공하는 기능을 추가 할 수 있습니다.
나머지 코드는 다음과 달라집니다.
// The bootstrapping process
var body = document.getElementsByTagName('body')[0];
// Check that our directive hasn't been compiled
function howmany(classname) {
return document.getElementsByClassName(classname).length;
}
우리가 무엇을하기 전에 test-directive
DOM에 클래스가 있는 요소 가 없어야하고, 완료 한 후에는 1이 될 것입니다.
console.log('before (should be 0):', howmany('test-directive'));
angular.element(document).ready(function() {
// Bootstrap the body, which loades the specified modules
// and compiled the DOM.
angular.bootstrap(body, ['app']);
// Our app is loaded and the DOM is compiled
console.log('after (should be 1):', howmany('test-directive'));
});
꽤 간단합니다. 문서가 준비 널 angular.bootstrap
앱의 루트 요소와 모듈 이름 배열로 호출 체계 .
실제로 함수를 모듈에 연결run
app
컴파일이 수행하면되기 전에 함수 가 실행되는 것을 볼 수 있습니다.
바이올린을 실행하고 콘솔을 보면 다음이 표시됩니다.
before (should be 0): 0
Compiling test-directive
Prelink
Postlink
after (should be 1): 1 <--- success!
Angular는 페이지의 로딩이 끝났을 때 신호를 보내는 방법을 제공하지 않습니다. 아마도 "완료"는 응용 프로그램에 따라 다를 수 있습니다 . 예를 들어, 계층 적 부분 트리가있는 경우 하나는 다른 하나를로드합니다. "완료"는 모든 항목이로드된다는 의미입니다. 모든 프레임 워크는 코드를 분석하고 여전히 대기 중이라는 것을 이해하는 데 어려움을 겪고있는 것입니다. 이를 확인하고 결정해야합니다.
각도 초기화가 시점을 평가할 때 정확한 솔루션을 평가합니다.
지시문은 다음과 달라집니다.
.directive('initialisation',['$rootScope',function($rootScope) {
return {
restrict: 'A',
link: function($scope) {
var to;
var listener = $scope.$watch(function() {
clearTimeout(to);
to = setTimeout(function () {
console.log('initialised');
listener();
$rootScope.$broadcast('initialised');
}, 50);
});
}
};
}]);
그런 다음 body
요소에 속성으로 추가 한 다음 사용을 수신 대기 할 수 있습니다.$scope.$on('initialised', fn)
더 이상 $ 다이제스트 사이클이 없을 때 응용 프로그램이 초기화되면 가정하여 작동합니다. $ watch는 모든 다이제스트주기마다 호출되는 타이머가 시작됩니다 ($ timeout이 아닌 setTimeout은 새 다이제스트주기가 트리거되지 않음). 제한 시간 복제 된 다이제스트주기가 발생하지 않은 애플리케이션이 초기화 된 것입니다.
satchmoruns 솔루션은 없던 관리하지 않습니다. (다이제스트 사이클이 시간 초과보다 오래 걸릴 수 있음) 내 솔루션이 필요하기가 쉬운 모듈을 추적 할 수 없습니다. 어쨌든 내 요구 사항에 대해 충분히 이해할 것입니다. 도움이 되길 바랍니다.
Angular UI Router를 사용 하는 경우 $viewContentLoaded
이벤트를 들을 수 있습니다 .
"$ viewContentLoaded- DOM이 발생하는 후 뷰가로드 시작 됩니다. 뷰의 '$ scope'가 생성됩니다." - 링크
$scope.$on('$viewContentLoaded',
function(event){ ... });
JQuery를 사용하여 각도의 DOM 조작을 관찰하고 내 앱 (내 앱 요약에 필요한 미리 정의되고 만족스러운 상황)에 대한 마무리를 설정했습니다. 예를 들어 ng-repeater가 7 개의 결과를 생성하고 사용에이를 위해 setInterval을 관찰하여 기능을 설정합니다.
$(document).ready(function(){
var interval = setInterval(function(){
if($("article").size() == 7){
myFunction();
clearInterval(interval);
}
},50);
});
ngRoute 모듈을 사용하지 않는 경우 , 즉 $ viewContentLoaded 이벤트 가 없습니다 .
다른 지시문 방법을 사용할 수 있습니다.
angular.module('someModule')
.directive('someDirective', someDirective);
someDirective.$inject = ['$rootScope', '$timeout']; //Inject services
function someDirective($rootScope, $timeout){
return {
restrict: "A",
priority: Number.MIN_SAFE_INTEGER, //Lowest priority
link : function(scope, element, attr){
$timeout(
function(){
$rootScope.$emit("Some:event");
}
);
}
};
}
trusktr의 답변 에 따르면 우선 순위가 가장습니다. 또한 $ timeout 은 Angular가 실행 전에 전체 이벤트 루프를 통해 실행 가능합니다.
응용 프로그램의 모든 범위에 지시문을 배치하고 필요한 리스너에게만 알릴 수 있기 때문에 $ rootScope가 사용되었습니다.
$ rootScope. $ emit는 리스너에서만 모든 $ rootScope. $에 대한 이벤트를 발생하고 있습니다. 흥미로운 부분은 $ rootScope. $ 방송은 모든 $의 rootScope를 알려 것입니다. 물론 $ 범위로에 $. 청취자에 $ 소스
Angular 팀 과이 Github 문제 에 따르면 :
이제 ng-view 및 ng-include에서 생성되는 $ viewContentLoaded 및 $ includeContentLoaded 이벤트가 있습니다. 나는 이것이 우리가 있다고 마쳤을 때 알 수있는 한 가깝다고 생각합니다.
이를 바탕으로 현재 수있는 방법으로는 불가능한 것 입니다. 즉, Angular가 즉시 이벤트를 제공했을 것입니다.
앱을 부팅 할 수 없습니다. 루트 범위에서 다이제스트주기를 실행하고 다이제스트주기 완료도 이벤트가 없습니다.
Angular 2 디자인 문서 에 따르면 :
다이제스트가 여러 개이기 때문에 모델이 여러 가지 구성 요소를 결정하고 알릴 수 없습니다. 알림이 데이터를 추가로 변경하여 바인딩 프로세스를 다시 시작할 수 있기 때문입니다.
이것에 따르면, 이것이 불가능하다는 사실은 Angular 2에서 다시 작성하기로 결정한 이유 하나입니다.
라우팅을 통해 주요 부분 이후 /에 의해로드 된 조각이 있습니다.
하위 부분이로드 된 후 함수를 실행해야 새로운 지시문을 작성하고 싶고 사용할 수 있습니다. ngIf
부모 부분의 컨트롤러 :
$scope.subIsLoaded = function() { /*do stuff*/; return true; };
하위 부분의 HTML
<element ng-if="subIsLoaded()"><!-- more html --></element>
서버 측 데이터 (JSP, PHP)를 사용하여 JS를 생성하려는 경우 컨트롤러를로드 할 때 자동으로로드되는 서비스를 추가 할 수 있습니다.
또한 모든 지시문이 초기화 될 때 / 링크 될 때 반응하려는 경우에 위의 제안 된 솔루션을 추가 할 수 있습니다.
module.factory('YourControllerInitService', function() {
// add your initialization logic here
// return empty service, because it will not be used
return {};
});
module.controller('YourController', function (YourControllerInitService) {
});
이것들은 모두 훌륭한 솔루션이지만, 현재 라우팅을 사용하고있는 솔루션이 가장 약간 약간 약간의 코드입니다. 'resolve'속성을 사용하여 경로를 트리거하기 전에 약속이 완료 될 때까지 기다리십시오. 예 :
$routeProvider
.when("/news", {
templateUrl: "newsView.html",
controller: "newsController",
resolve: {
message: function(messageService){
return messageService.getMessage();
}
}
})
전체 문서를 보려면 여기를 클릭하십시오 -K. Scott Allen의 신용
이 예제로 당신을 도울 수 있습니까?
사용자 정의 fancybox에서 보간 된 값으로 내용을 보여줍니다.
서비스에서 "open"fancybox 방법으로
open: function(html, $compile) {
var el = angular.element(html);
var compiledEl = $compile(el);
$.fancybox.open(el);
}
$ compile은 저장된 데이터를 반환합니다. 검색된 데이터를 확인할 수 있습니다.
참고 URL : https://stackoverflow.com/questions/14968690/sending-event-when-angularjs-finished-loading
'IT' 카테고리의 다른 글
다른 목록 ID에서 목록 정렬 (0) | 2020.07.25 |
---|---|
MD5 해시 계산 (0) | 2020.07.25 |
TypeScript에서 여러 유형으로 배열 정의 (0) | 2020.07.25 |
angular2 tslint 경고를 중지하기 위해 구성 요소의 기본 접두사를 변경하는 방법 (0) | 2020.07.25 |
Python에서 urllib을 사용하여 웹 사이트가 404 또는 200인지 여부를 확인하십시오. (0) | 2020.07.25 |