สงสัยว่าอะไรคือวิธีที่ดีที่สุดในการตรวจจับการสิ้นสุดของการโหลดหน้า / การบูตสตราปเมื่อคำสั่งทั้งหมดเสร็จสิ้นการรวบรวม / เชื่อมโยง
มีเหตุการณ์ใดแล้ว? ฉันควรใช้ฟังก์ชัน bootstrap มากเกินไปหรือไม่
สงสัยว่าอะไรคือวิธีที่ดีที่สุดในการตรวจจับการสิ้นสุดของการโหลดหน้า / การบูตสตราปเมื่อคำสั่งทั้งหมดเสร็จสิ้นการรวบรวม / เชื่อมโยง
มีเหตุการณ์ใดแล้ว? ฉันควรใช้ฟังก์ชัน bootstrap มากเกินไปหรือไม่
คำตอบ:
แค่ลางสังหรณ์: ทำไมไม่ลองดูว่าคำสั่ง ngCloak ทำอย่างไร? เห็นได้ชัดว่าคำสั่ง ngCloak จัดการเพื่อแสดงเนื้อหาหลังจากโหลดสิ่งต่างๆแล้ว ฉันพนันได้เลยว่าการดู ngCloak จะนำไปสู่คำตอบที่แน่นอน ...
แก้ไข 1 ชั่วโมงต่อมา: โอเคฉันดูngCloakแล้วมันสั้นมาก สิ่งที่เห็นได้ชัดคือฟังก์ชันคอมไพล์จะไม่ถูกเรียกใช้งานจนกว่านิพจน์ {{template}} จะได้รับการประเมิน (เช่นเทมเพลตที่โหลด) ดังนั้นฟังก์ชันการทำงานที่ดีของคำสั่ง ngCloak
การคาดเดาที่มีการศึกษาของฉันคือเพียงสร้างคำสั่งด้วยความเรียบง่ายแบบเดียวกันของ ngCloak จากนั้นในฟังก์ชันคอมไพล์ของคุณให้ทำสิ่งที่คุณต้องการทำ :) วางคำสั่งไว้ที่องค์ประกอบหลักของแอปของคุณ คุณสามารถเรียกคำสั่งบางอย่างเช่น myOnload และใช้เป็นแอตทริบิวต์ my-onload ฟังก์ชันคอมไพล์จะดำเนินการเมื่อรวบรวมเทมเพลตแล้ว (นิพจน์ที่ประเมินและโหลดเทมเพลตย่อยแล้ว)
แก้ไข 23 ชั่วโมงต่อมา: โอเคฉันจึงค้นคว้าและถามคำถามของตัวเองด้วย คำถามที่ฉันถามเกี่ยวข้องโดยอ้อมกับคำถามนี้ แต่บังเอิญนำฉันไปสู่คำตอบที่ช่วยแก้คำถามนี้ได้
คำตอบคือคุณสามารถสร้างคำสั่งง่ายๆและใส่รหัสของคุณในฟังก์ชันลิงก์ของคำสั่งซึ่ง (สำหรับกรณีการใช้งานส่วนใหญ่อธิบายไว้ด้านล่าง) จะทำงานเมื่อองค์ประกอบของคุณพร้อม / โหลด ขึ้นอยู่กับรายละเอียดของจอชของการสั่งซื้อที่รวบรวมและเชื่อมโยงการทำงานจะดำเนินการ ,
หากคุณมีมาร์กอัปนี้:
<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
ตามค่าเริ่มต้นฟังก์ชัน "ลิงก์" แบบตรงคือโพสต์ลิงก์ดังนั้นฟังก์ชันลิงก์ของ directive1 ภายนอกของคุณจะไม่ทำงานจนกว่าฟังก์ชันลิงก์ของ directive2 ภายในจะทำงาน นั่นเป็นเหตุผลที่เราบอกว่าการจัดการ DOM ในโพสต์ลิงก์นั้นปลอดภัยเท่านั้น ดังนั้นในคำถามเดิมไม่ควรมีปัญหาในการเข้าถึง 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 พวกเขาสร้างขอบเขตของตนเองและคำสั่งของคุณอาจไม่เริ่มทำงาน ตัวอย่างเช่นถ้าคุณใส่คำสั่ง ngElementReady ใหม่ของเราในองค์ประกอบที่มี ngIf ด้วยและเงื่อนไขของ ngIf ประเมินว่าเป็นเท็จคำสั่ง ngElementReady ของเราจะไม่ถูกโหลด หรือตัวอย่างเช่นหากคุณใส่คำสั่ง ngElementReady ใหม่ของเราในองค์ประกอบที่มีคำสั่ง ngInclude ด้วยคำสั่งของเราจะไม่ถูกโหลดหากไม่มีเทมเพลตสำหรับ 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
อาจดี แต่ไม่ใช่สำหรับองค์ประกอบเฉพาะซึ่งในกรณีนี้ฟังก์ชันลิงก์จะดีกว่า
แก้ไขห้าเดือนต่อมา 17 ต.ค. เวลา 8:11 PST:
สิ่งนี้ใช้ไม่ได้กับบางส่วนที่โหลดแบบอะซิงโครนัส คุณจะต้องเพิ่มการทำบัญชีลงในบางส่วนของคุณ (เช่นวิธีหนึ่งคือทำให้แต่ละส่วนติดตามเมื่อโหลดเนื้อหาเสร็จแล้วจึงปล่อยเหตุการณ์ออกมาเพื่อให้ขอบเขตหลักสามารถนับจำนวนชิ้นส่วนที่โหลดและสุดท้ายทำตามที่ต้องการ ทำหลังจากโหลดบางส่วนแล้ว)
แก้ไข 23 ต.ค. เวลา 22: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);
}
});
}
};
});
แก้ไข 24 ต.ค. เวลา 00: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
คงเกิดขึ้นหลังจากที่ตัวยึดตำแหน่งถูกแทนที่ในตอนแรก (การสรุป $ สามารถเกิดขึ้นได้ถึง 10 ครั้งจนกว่าข้อมูลจะหยุดเปลี่ยนแปลง) เหมาะสำหรับกรณีการใช้งานส่วนใหญ่
แก้ไข 31 ต.ค. เวลา 19: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: /programming/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!
run
ยิงก่อนคำสั่งและเมื่อไฟทำงาน html ไม่ได้อยู่ที่นั่นทั้งหมด
$timeout( initMyPlugins,0)
งานภายในคำสั่งของฉัน html ทั้งหมดที่ฉันต้องการอยู่ที่นั่น
เชิงมุมไม่ได้ให้วิธีการที่จะส่งสัญญาณเมื่อมีการโหลดหน้าเว็บเสร็จแล้วอาจจะเพราะ"สำเร็จรูป" ขึ้นอยู่กับการใช้งานของคุณ ตัวอย่างเช่นหากคุณมีโครงสร้างแบบลำดับชั้นของบางส่วนหนึ่งรายการจะโหลดส่วนอื่น ๆ "เสร็จสิ้น" หมายความว่าโหลดทั้งหมดแล้ว เฟรมเวิร์กใด ๆ จะมีปัญหาในการวิเคราะห์โค้ดของคุณและทำความเข้าใจว่าทุกอย่างเสร็จเรียบร้อยแล้วหรือยังรออยู่ สำหรับสิ่งนั้นคุณจะต้องระบุตรรกะเฉพาะแอปพลิเคชันเพื่อตรวจสอบและพิจารณาว่า
ฉันได้หาวิธีแก้ปัญหาที่ค่อนข้างแม่นยำในการประเมินเมื่อการเริ่มต้นเชิงมุมเสร็จสมบูรณ์
คำสั่งคือ:
.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 เรียกว่าทุก ๆ รอบการย่อยดังนั้นตัวจับเวลาจึงเริ่มทำงาน (setTimeout ไม่ใช่ $ timeout เพื่อไม่ให้เกิดรอบการย่อยใหม่) หากวงจรการแยกย่อยไม่เกิดขึ้นภายในระยะหมดเวลาแสดงว่าแอปพลิเคชันได้เริ่มต้นแล้ว
เห็นได้ชัดว่าไม่แม่นยำเท่าโซลูชัน satchmoruns (เนื่องจากเป็นไปได้ที่วงจรการย่อยจะใช้เวลานานกว่าการหมดเวลา) แต่โซลูชันของฉันไม่ต้องการให้คุณติดตามโมดูลซึ่งทำให้ง่ายต่อการจัดการ (โดยเฉพาะสำหรับโครงการขนาดใหญ่ ) อย่างไรก็ตามดูเหมือนว่าจะแม่นยำเพียงพอสำหรับความต้องการของฉัน หวังว่าจะช่วยได้
หากคุณใช้Angular UI Routerคุณสามารถฟัง$viewContentLoaded
เหตุการณ์ได้
"$ viewContentLoaded - เริ่มทำงานเมื่อมุมมองถูกโหลดหลังจากที่ DOM แสดงผล " $ scope "ของมุมมองจะแสดงเหตุการณ์" - ลิงค์
$scope.$on('$viewContentLoaded',
function(event){ ... });
ฉันสังเกตการจัดการ DOM ของเชิงมุมด้วย JQuery และฉันได้ตั้งค่าการสิ้นสุดสำหรับแอพของฉัน (สถานการณ์ที่กำหนดไว้ล่วงหน้าและน่าพอใจบางอย่างที่ฉันต้องการสำหรับแอพนามธรรมของฉัน) ตัวอย่างเช่นฉันคาดหวังว่า 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จึงมีลำดับความสำคัญต่ำสุด การหมดเวลาบวก$จะทำให้ Angular ทำงานผ่านลูปเหตุการณ์ทั้งหมดก่อนดำเนินการเรียกกลับ
ใช้ $ rootScopeเนื่องจากอนุญาตให้วางคำสั่งในขอบเขตใด ๆ ของแอปพลิเคชันและแจ้งผู้ฟังที่จำเป็นเท่านั้น
$ rootScope $ emit จะเริ่มเหตุการณ์สำหรับ $ rootScope $ ทั้งหมดสำหรับผู้ฟังเท่านั้น ส่วนที่น่าสนใจคือ $ rootScope $ broadcast จะแจ้ง $ rootScope ทั้งหมด $ on เช่นเดียวกับ $ scope $ บนผู้ฟัง Source
ตามที่ทีมเชิงมุมและปัญหา Github :
ตอนนี้เรามีเหตุการณ์ $ viewContentLoaded และ $ includeContentLoaded ที่ปล่อยออกมาใน ng-view และ ng-include ตามลำดับ ฉันคิดว่านี่เป็นเรื่องใกล้ตัวมากที่สุดเท่าที่เราจะสามารถรู้ได้เมื่อเรารวบรวมเสร็จแล้ว
จากสิ่งนี้ดูเหมือนว่าในขณะนี้ไม่สามารถทำได้ด้วยวิธีที่เชื่อถือได้มิฉะนั้น Angular จะจัดให้มีกิจกรรมนอกกรอบ
การบูตแอปหมายถึงการเรียกใช้วงจรการย่อยในขอบเขตรูทและยังไม่มีเหตุการณ์ที่เสร็จสิ้นของวงจรการย่อย
ตามเอกสารการออกแบบ Angular 2 :
เนื่องจากการย่อยหลายรายการจึงไม่สามารถระบุและแจ้งส่วนประกอบได้ว่าโมเดลมีเสถียรภาพ เนื่องจากการแจ้งเตือนสามารถเปลี่ยนแปลงข้อมูลเพิ่มเติมซึ่งสามารถเริ่มกระบวนการผูกใหม่ได้
ด้วยเหตุนี้ความจริงที่ว่าสิ่งนี้เป็นไปไม่ได้จึงเป็นสาเหตุหนึ่งที่ทำให้ตัดสินใจเขียนซ้ำใน Angular 2
ฉันมีส่วนที่ได้รับการโหลดหลังจาก / โดยบางส่วนหลักที่เข้ามาผ่านการกำหนดเส้นทาง
ฉันต้องการเรียกใช้ฟังก์ชันหลังจากโหลดส่วนย่อยนั้นแล้วและฉันไม่ต้องการเขียนคำสั่งใหม่และคิดว่าคุณสามารถใช้หน้าด้าน ngIf
ผู้ควบคุมบางส่วนของผู้ปกครอง:
$scope.subIsLoaded = function() { /*do stuff*/; return true; };
HTML ของส่วนย่อย
<element ng-if="subIsLoaded()"><!-- more html --></element>
หากคุณต้องการสร้าง JS ด้วยข้อมูลฝั่งเซิร์ฟเวอร์ (JSP, PHP) คุณสามารถเพิ่มตรรกะของคุณลงในบริการซึ่งจะโหลดโดยอัตโนมัติเมื่อโหลดคอนโทรลเลอร์ของคุณ
นอกจากนี้หากคุณต้องการตอบสนองเมื่อคำสั่งทั้งหมดเสร็จสิ้นการคอมไพล์ / การเชื่อมโยงคุณสามารถเพิ่มโซลูชันที่เสนอที่เหมาะสมด้านบนในตรรกะการเริ่มต้น
module.factory('YourControllerInitService', function() {
// add your initialization logic here
// return empty service, because it will not be used
return {};
});
module.controller('YourController', function (YourControllerInitService) {
});
ทั้งหมดนี้เป็นโซลูชันที่ยอดเยี่ยมอย่างไรก็ตามหากคุณกำลังใช้ Routing อยู่ฉันพบว่าโซลูชันนี้เป็นวิธีที่ง่ายที่สุดและจำเป็นต้องใช้รหัสน้อยที่สุด ใช้คุณสมบัติ 'แก้ไข' เพื่อรอให้คำสัญญาเสร็จสมบูรณ์ก่อนที่จะเรียกใช้เส้นทาง เช่น
$routeProvider
.when("/news", {
templateUrl: "newsView.html",
controller: "newsController",
resolve: {
message: function(messageService){
return messageService.getMessage();
}
}
})
คลิกที่นี่เพื่อดูเอกสารฉบับเต็ม - มอบเครดิตให้กับ K. Scott Allen
ฉันสามารถช่วยคุณได้จากตัวอย่างนี้
ในกล่องแฟนซีที่กำหนดเองฉันแสดงเนื้อหาด้วยค่าที่ถูกแก้ไข
ในบริการในวิธีการแฟนซีบ็อกซ์ "เปิด" ฉันทำ
open: function(html, $compile) {
var el = angular.element(html);
var compiledEl = $compile(el);
$.fancybox.open(el);
}
$ compile ส่งคืนข้อมูลที่คอมไพล์แล้ว คุณสามารถตรวจสอบข้อมูลที่รวบรวมได้