เหตุการณ์ AngularJs ที่จะเรียกหลังจากโหลดเนื้อหาแล้ว


163

ฉันมีฟังก์ชั่นที่ฉันต้องการโทรหลังจากโหลดเนื้อหาหน้า ฉันอ่านเกี่ยวกับ $ viewContentLoaded และใช้ไม่ได้สำหรับฉัน ฉันกำลังมองหาบางอย่างเช่น

document.addEventListener('DOMContentLoaded', function () { 
     //Content goes here 
}, false);

การโทรด้านบนไม่ทำงานสำหรับฉันในตัวควบคุม AngularJs


คำตอบ:


163

ตามเอกสารของ$ viewContentLoadedมันควรจะทำงาน

ปล่อยออกมาทุกครั้งที่มีการโหลดเนื้อหา ngView

$viewContentLoaded เหตุการณ์ถูกปล่อยออกมาซึ่งหมายความว่าจะได้รับเหตุการณ์นี้คุณต้องการตัวควบคุมหลักเช่น

<div ng-controller="MainCtrl">
  <div ng-view></div>
</div>

จากMainCtrlคุณสามารถฟังเหตุการณ์

  $scope.$on('$viewContentLoaded', function(){
    //Here your view content is fully loaded !!
  });

ตรวจสอบการสาธิต


59
ปัญหาเกี่ยวกับวิธีการนี้คือตัวควบคุมยังไม่ได้เริ่มต้นอย่างเต็มที่ ณ จุดนี้
Ash Blue

12
@Reza เขาถูกต้องเหตุการณ์นี้จะเริ่มทำงานเมื่อมีการเพิ่ม dom แต่ก่อนที่ angular จะเสร็จสิ้นการประมวลผล dom คุณสามารถทดสอบสิ่งนี้ได้โดยการเพิ่ม id หรือคลาสเป็นตัวแปรเชิงมุมและลองหามันใน $ viewContentLoaded ด้วย jQuery คุณจะไม่พบมัน
โทมัส Kekeisen

1
@Reza ใช่โทมัสนั้นถูกต้ององค์ประกอบฟอร์มไม่สามารถเข้าถึงภายในคำสั่ง $ viewContentLoaded, $ scope.formName.elementName. $ setValidity ("validateRule", false); จะโยน "TypeError: ไม่สามารถอ่านคุณสมบัติ 'elementName' จาก undefined"
Mussammil

2
สิ่งนี้สามารถเรียกได้ในระดับ $ rootScope แทนที่จะเป็น $ scope $ on ควรเป็น $ rootScope $ $ และด้านในของ app.run () block
Vil

4
ตัวเลือกนี้จะไม่ทำงานเมื่อคุณมีng-repeatและคำสั่งซ้อนหลายอย่างที่จะสร้าง HTML / เนื้อหาตามลูปและเงื่อนไขที่ซับซ้อน การแสดงผลจะดำเนินต่อไประยะหนึ่งแม้หลังจาก$viewContentLoadedเหตุการณ์ถูกเรียก คุณจะมั่นใจได้อย่างไรว่าองค์ประกอบทั้งหมดได้รับการแสดงผลอย่างสมบูรณ์จากนั้นรันโค้ดบางอย่าง ข้อเสนอแนะใด ๆ
tarekahf

104

เชิงมุม <1.6.X

angular.element(document).ready(function () {
    console.log('page loading completed');
});

เชิงมุม> = 1.6.X

angular.element(function () {
    console.log('page loading completed');
});

สิ่งนี้มีอยู่ภายใน app.js หรือไม่
zcoon

3
คุณสามารถฟังได้ใน controllers.js ของคุณ
hariszaman

2
ใช้งานได้ดีในไฟล์ app.js หลักเช่นกัน
Loubot

คำตอบนั้นใช้ได้สำหรับฉัน! เพิ่งเห็นว่าในหน้าองค์ประกอบเอกสาร 'ready () (เลิกใช้แล้วให้ใช้ angular.element (โทรกลับ) แทน angular.element (เอกสาร). ready (callback))'
Lovera

สิ่งนี้ใช้ได้สำหรับฉัน วิธีการตอบรับที่ยอมรับใช้ไม่ได้กับคอนโทรลเลอร์
Fabiano

76

คงที่ - 2015.06.09

ใช้คำสั่งและreadyวิธีองค์ประกอบเชิงมุมดังนี้:

js

.directive( 'elemReady', function( $parse ) {
   return {
       restrict: 'A',
       link: function( $scope, elem, attrs ) {    
          elem.ready(function(){
            $scope.$apply(function(){
                var func = $parse(attrs.elemReady);
                func($scope);
            })
          })
       }
    }
})

HTML

<div elem-ready="someMethod()"></div>

หรือสำหรับผู้ที่ใช้ตัวควบคุมเป็นไวยากรณ์ ...

<div elem-ready="vm.someMethod()"></div>

ประโยชน์ของสิ่งนี้คือคุณสามารถเป็นแบบกว้างหรือละเอียดด้วย UI ของคุณตามที่คุณต้องการและคุณกำลังลบตรรกะ DOM จากตัวควบคุมของคุณ ฉันจะโต้แย้งว่านี่เป็นวิธีเชิงมุมที่แนะนำ

คุณอาจจำเป็นต้องจัดลำดับความสำคัญของคำสั่งนี้ในกรณีที่คุณมีคำสั่งอื่น ๆ ที่ทำงานบนโหนดเดียวกัน


ดูเหมือนว่าจะเป็นวิธีแก้ปัญหาที่ดีจริงๆ แต่ฉันไม่สามารถใช้งานได้ มันสำลักที่elem.ready( $scope.$apply( readyFunc( $scope ))); ความคิดใด ๆ ที่อาจเป็นเพราะอะไร อาจมีการอัพเดทมุมเชิงมุมเกิดขึ้นหรือไม่ อย่างไรก็ตาม - มันเป็นวิธีการที่สง่างามถ้ามันสามารถทำงานได้
domoarigato

1
อืมฉันเห็นสิ่งที่เป็นปัญหา มีการพิมพ์ผิดที่attrs.onReadyควรจะเป็นในขณะนี้ อีกประเด็นคือฉันเรียกมันว่าขี้ขลาด .... ... สิ่งที่ฉันได้รับจากการแปลงกาแฟจากหน่วยความจำไปเป็น JS
jusopi

1
ฉันคิดว่าในบางกรณีที่อาจใช้ได้ แต่ข้อโต้แย้งของฉันคือ: ฉันคิดว่าความคาดหวังของรหัสของเขาเมื่อมองเพียงอย่างเดียวคือการคืนค่าข้อความที่จะแสดงใน DOM ดังนั้นต้องใช้ความระมัดระวัง มันไม่ได้ช่วยให้ระยะเวลาใด ๆ ในแง่ของการจัดลำดับความสำคัญสั่งคุณจะติดอยู่ในระดับที่ควบคุมเว้นแต่คุณจะใช้$timeout; คุณกำลังสร้าง addt อย่างชัดเจน โหนด DOM เพียงเพื่อดำเนินการตรรกะที่ไม่ใช่โดม; มันสามารถนำกลับมาใช้ใหม่ได้หากวิธีนั้นอยู่ไกลกว่าในลำดับชั้น $ scope เช่นว่าขอบเขตเด็กได้รับมรดกฉันแค่คิดว่ามันดูไม่ดีในมุมมองของ NG;
jusopi

5
ทำงานให้ฉันหลังจากเพิ่มรอบ$timeout(function() {}) elem.ready()มิฉะนั้นจะเกิด$digest already in progressข้อผิดพลาดในการขว้างปา แต่อย่างไรก็ตามขอบคุณมาก! ฉันดิ้นรนกับสิ่งนี้ในชั่วโมงที่ผ่านมา
rkrishnan

1
การขุดผ่าน $ scope ดูเหมือนจะว่างเปล่า ความคิดใด ๆ
MiloTheGreat

66

คุณสามารถเรียกมันได้โดยตรงโดยเพิ่ม{{YourFunction()}}หลังจากองค์ประกอบ HTML

Plunker Linkนี่คือ


6
คุณช่วยอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับโซลูชันที่คุณให้ได้ไหม
abarisone

ฉันคิดว่าคุณต้องการเรียกใช้ฟังก์ชันเมื่อโหลดองค์ประกอบ html นั้น ดังนั้นเรียกฟังก์ชั่นดังกล่าวข้างต้น หากการเดาของฉันถูกต้องเกี่ยวกับข้อสงสัยของคุณการดำเนินการนี้จะเป็นอย่างอื่นโปรดอธิบายคำถามของคุณให้ละเอียด :)
สีน้ำเงิน

14
เมื่อเรียกใช้ฟังก์ชั่นเช่นนี้ ตรวจสอบให้แน่ใจว่าถูกเรียกใช้หนึ่งครั้งหรืออย่างอื่นวงจรการย่อยจะทำงานไม่สิ้นสุดและแสดงข้อผิดพลาด
Ashan

2
ฉันชอบโซลูชันนี้มันง่ายจริงๆ
Kamuran Sönecek

1
นี่ยอดเยี่ยม - ปัญหาเดียวเท่านั้น ปรากฏว่าฟังก์ชั่นของฉันทำงาน 5 ครั้งเมื่อฉันใช้สิ่งนี้ ฉันเพิ่มเคาน์เตอร์ดังนั้นมันจึงทำงานได้ดี แต่ฉันแค่สงสัยว่าถ้าใครรู้ว่าทำไมมันถึงเกิดขึ้น ... ดูเหมือนว่าคุณจะแปลกไปไหม?
itchyspacesuit

22

ฉันต้องใช้ตรรกะนี้ในขณะที่จัดการกับชาร์ตของ google สิ่งที่ฉันทำคือว่าในตอนท้ายของ html ของฉันภายในคำจำกัดความของตัวควบคุมที่ฉันเพิ่ม

  <body>
         -- some html here -- 
--and at the end or where ever you want --
          <div ng-init="FunCall()"></div>
    </body>

และในฟังก์ชั่นนั้นเรียกตรรกะของคุณ

$scope.FunCall = function () {
        alert("Called");
}

ฉันใช้สิ่งนี้ แต่ที่ด้านบนสุดของหน้า init จำเป็นต้องโหลด div บางส่วนแล้วโดยการย้าย ng-init ไปที่ด้านล่างของหน้าเพื่อแก้ไขปัญหาของฉันคำแนะนำที่ดีและเหมาะสม
Gurnard

เพียงตอบที่ช่วยให้ฉันกับปัญหาของฉัน (jQuery มือถือเลือกว่างเปล่า)
ไกเซอร์

นี่คือคำตอบที่แท้จริงเนื่องจากปรับให้เหมาะกับการควบคุมที่โหลดแบบไดนามิกและใช้งานง่ายสุด ๆ
Jason Sebring

คำตอบนี้ช่วยฉันได้สักระยะดังนั้นฉันจึงสง่างามและมีประสิทธิภาพสำหรับกรณีการใช้งานของฉัน
Sello

4
var myM = angular.module('data-module');

myM.directive('myDirect',['$document', function( $document ){

    function link( scope , element , attrs ){

        element.ready( function(){

        } );

        scope.$on( '$viewContentLoaded' , function(){

            console.log(" ===> Called on View Load ") ;

        } );

    }

    return {
        link: link
    };

}] );

วิธีการดังกล่าวข้างต้นทำงานสำหรับฉัน


3

คุณสามารถเรียกใช้งานเหตุการณ์ onload ในรูปแบบจาวาสคริปต์ได้ที่ js angular เหตุการณ์ ng-load นี้สามารถใช้กับองค์ประกอบ dom ใด ๆ เช่น div, span, body, iframe, img และอื่น ๆ ต่อไปนี้เป็นลิงก์เพื่อเพิ่ม ng-load ในโครงการที่มีอยู่ของคุณ

ดาวน์โหลด ng-load สำหรับ angular js

ต่อไปนี้เป็นตัวอย่างสำหรับ iframe เมื่อโหลด testCallbackFunction แล้ว จะถูกเรียกใช้ในคอนโทรลเลอร์

ตัวอย่าง

JS

    // include the `ngLoad` module
    var app = angular.module('myApp', ['ngLoad']);
    app.controller('myCtrl', function($scope) {
        $scope.testCallbackFunction = function() {
          //TODO : Things to do once Element is loaded
        };

    });  

HTML

  <div ng-app='myApp' ng-controller='myCtrl'> 
      <iframe src="test.html" ng-load callback="testCallbackFunction()">  
  </div>

โปรดเพิ่มโค้ดตัวอย่างบางส่วนเพื่อแสดงว่า OP สามารถแก้ไขปัญหาได้อย่างไร
jro

@jro อัปเดต ans ของฉัน หวังว่ามันจะเป็นประโยชน์ :)
Darshan Jain

2

หากคุณได้รับข้อผิดพลาดระหว่างดำเนินการกับ $ Digest สิ่งนี้อาจช่วย:

return {
        restrict: 'A',
        link: function( $scope, elem, attrs ) {
            elem.ready(function(){

                if(!$scope.$$phase) {
                    $scope.$apply(function(){
                        var func = $parse(attrs.elemReady);
                        func($scope);
                    })
                }
                else {

                    var func = $parse(attrs.elemReady);
                    func($scope);
                }

            })
        }
    }

0

การรันหลังจากการโหลดหน้าเว็บควรได้รับความพึงพอใจบางส่วนด้วยการตั้งค่าฟังเหตุการณ์ให้เป็นเหตุการณ์โหลดหน้าต่าง

window.addEventListener("load",function()...)

ภายในmodule.run(function()...)เชิงมุมคุณจะสามารถเข้าถึงโครงสร้างโมดูลและการพึ่งพาได้ทั้งหมด

คุณสามารถbroadcastและemitกิจกรรมสำหรับบริดจ์การสื่อสาร

ตัวอย่างเช่น:

  • ชุดโมดูลเหตุการณ์ onload และสร้างตรรกะ
  • โมดูลการออกอากาศเหตุการณ์ไปยังตัวควบคุมเมื่อจำเป็นต้องใช้ตรรกะ
  • ตัวควบคุมจะรับฟังและดำเนินการตรรกะของตัวเองตามกระบวนการโมดูลโหลด

0

ฉันใช้{{myFunction()}}ในแม่แบบ แต่ก็พบวิธีอื่นที่นี่โดยใช้$timeoutภายในตัวควบคุม คิดว่าฉันจะแบ่งปันมันใช้งานได้ดีสำหรับฉัน

angular.module('myApp').controller('myCtrl', ['$timeout',
function($timeout) {
var self = this;

self.controllerFunction = function () { alert('controller function');}

$timeout(function () {
    var vanillaFunction = function () { alert('vanilla function'); }();
    self.controllerFunction();
});

}]);

ฉันลองคำตอบทั้งหมดที่นี่และด้วยเหตุผลบางอย่างการหมดเวลา $ เป็นสิ่งเดียวที่ทำงานให้ฉัน ไม่แน่ใจว่าทำไม แต่อาจมีบางอย่างที่เกี่ยวข้องกับ ng-include และเวลาในการเริ่มบริการ
Drellgor

ฉันได้เพิ่มเครื่องหมายบวกสำหรับ {{myFunction ()}}
commonpike

0

หากคุณต้องการให้องค์ประกอบบางอย่างโหลดสมบูรณ์ให้ใช้ ng-init บนองค์ประกอบนั้น

เช่น <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

ควรมีฟังก์ชัน initModalFacultyInfo () ในตัวควบคุม


0

ฉันพบว่าหากคุณมีมุมมองแบบซ้อน - $ viewContentLoaded จะถูกเรียกใช้สำหรับมุมมองแบบซ้อนทุกมุมมอง ฉันได้สร้างวิธีแก้ปัญหานี้เพื่อค้นหา $ viewContentLoaded สุดท้าย ดูเหมือนว่าจะทำงานได้ดีสำหรับการตั้งค่า $ window.prerenderReady ตามที่ Prerender กำหนด (ไปที่. run () ใน app.js หลัก):

// Trigger $window.prerenderReady once page is stable
// Note that since we have nested views - $viewContentLoaded is fired multiple
// times and we need to go around this problem
var viewContentLoads = 0;
var checkReady = function(previousContentLoads) {
  var currentContentLoads = Number(viewContentLoads) + 0; // Create a local copy of the number of loads
  if (previousContentLoads === currentContentLoads) { // Check if we are in a steady state
    $window.prerenderReady = true; // Raise the flag saying we are ready
  } else {
    if ($window.prerenderReady || currentContentLoads > 20) return; // Runaway check
    $timeout(function() {checkReady(currentContentLoads);}, 100); // Wait 100ms and recheck
  }
};
$rootScope.$on('$stateChangeSuccess', function() {
  checkReady(-1); // Changed the state - ready to listen for end of render
});
$rootScope.$on('$viewContentLoaded', function() {
  viewContentLoads ++;
});

0
var myTestApp = angular.module("myTestApp", []); 
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
 alert("is called on page load.");
};
});

ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
rollstuhlfahrer

0

วิธีแก้ปัญหาที่เหมาะกับฉันมีดังต่อไปนี้

app.directive('onFinishRender', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                    if (!!attr.onFinishRender) {
                        $parse(attr.onFinishRender)(scope);
                    }
                });
            }

            if (!!attr.onStartRender) {
                if (scope.$first === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatStarted');
                        if (!!attr.onStartRender) {
                            $parse(attr.onStartRender)(scope);
                        }
                    });
                }
            }
        }
    }
}]);

รหัสคอนโทรลเลอร์มีดังต่อไปนี้

$scope.crearTooltip = function () {
     $('[data-toggle="popover"]').popover();
}

รหัส Html มีดังต่อไปนี้

<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">

-31

ฉันใช้setIntervalเพื่อรอเนื้อหาที่โหลด ฉันหวังว่านี่จะช่วยคุณแก้ปัญหานั้นได้

var $audio = $('#audio');
var src = $audio.attr('src');
var a;
a = window.setInterval(function(){
    src = $audio.attr('src');
    if(src != undefined){
        window.clearInterval(a);
        $('audio').mediaelementplayer({
            audioWidth: '100%'
        });
    }
}, 0);

13
ผู้คนยังคงแนะนำsetIntervalวิธีแก้ปัญหาในปี 2559หรือไม่
Zachary Dahan

แต่ไม่มี api ง่ายใน agular ... วิธีการ .. ทำอย่างไร
Piotr Kula
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.