Sự kiện AngularJs để gọi sau khi nội dung được tải


163

Tôi có một chức năng mà tôi muốn gọi sau khi nội dung trang được tải. Tôi đã đọc về $ viewContentLoaded và nó không hoạt động với tôi. Tôi đang tìm kiếm một cái gì đó như

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

Cuộc gọi trên không hoạt động với tôi trong bộ điều khiển AngularJs.


1
Điều này hoạt động tốt stackoverflow.com/q/14968690/6521116
Kris Roofe

Câu trả lời:


163

Theo tài liệu của $ viewContentLoaded , nó được cho là hoạt động

Phát ra mỗi khi nội dung ngView được tải lại.

$viewContentLoaded sự kiện được phát ra có nghĩa là để nhận sự kiện này, bạn cần một bộ điều khiển chính như

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

Từ MainCtrlbạn có thể nghe sự kiện

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

Kiểm tra bản demo


59
Vấn đề với phương pháp này là các bộ điều khiển chưa được khởi tạo hoàn toàn vào thời điểm này.
Ash Blue

12
@Reza Anh ấy đúng, sự kiện này được kích hoạt khi dom được thêm vào nhưng trước khi góc đã xử lý xong dom. Bạn có thể kiểm tra điều này bằng cách thêm id hoặc class dưới dạng biến góc và thử tìm nó trong $ viewContentLoaded với jQuery. Bạn sẽ không tìm thấy nó.
Thomas Kekeisen

1
@Reza có, Thomas đúng là phần tử biểu mẫu không thể truy cập bên trong $ viewContentLoaded, $ scope.formName.elementName. $ SetValids ("validateRule", false); sẽ ném "TypeError: Không thể đọc thuộc tính 'ElementName' của không xác định"
Mussammil

2
Điều tương tự có thể được gọi ở mức $ rootScope. Thay vì $ scope. $ On, nó phải là $ rootScope. $ Trên và bên trong khối app.run ()
Vil

4
Tùy chọn này sẽ không hoạt động khi bạn có ng-repeatvà một số chỉ thị lồng nhau sẽ tạo HTML / Nội dung dựa trên các vòng lặp và điều kiện phức tạp. Kết xuất tiếp tục trong một thời gian, ngay cả sau khi $viewContentLoadedsự kiện được kích hoạt. Làm thế nào bạn có thể đảm bảo rằng tất cả các yếu tố đã được hiển thị đầy đủ sau đó thực thi mã nhất định? Bất kỳ thông tin phản hồi?
tarekahf

104

Góc <1.6.X

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

Góc> = 1.6.X

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

Điều này có đi trong app.js không?
zcoon

3
bạn có thể nghe nó trong bộ điều khiển của mình
hariszaman

2
Hoạt động ok trong tệp app.js chính quá.
Loubot

Câu trả lời đó có tác dụng với tôi! Chỉ cần thấy rằng trên trang phần tử tài liệu 'ready () (không dùng nữa, sử dụng angular.element (gọi lại) thay vì angular.element (tài liệu). Đã (gọi lại))'
Lovera

Điều này làm việc cho tôi. Phương pháp trả lời được chấp nhận không hoạt động bên trong bộ điều khiển.
Fabiano

76

cố định - 2015,06,09

Sử dụng một chỉ thị và readyphương pháp phần tử góc như vậy:

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>

hoặc cho những người sử dụng cú pháp như bộ điều khiển ...

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

Lợi ích của việc này là bạn có thể rộng hoặc chi tiết với giao diện người dùng của bạn như bạn muốn và bạn đang loại bỏ logic DOM khỏi bộ điều khiển của mình. Tôi sẽ tranh luận đây là cách Angular được đề nghị .

Bạn có thể cần ưu tiên chỉ thị này trong trường hợp bạn có các lệnh khác hoạt động trên cùng một nút.


Đây có vẻ là một giải pháp thực sự tốt, nhưng tôi không thể làm cho nó hoạt động được. Nó nghẹn ngào với elem.ready( $scope.$apply( readyFunc( $scope ))); bất kỳ ý tưởng tại sao đó có thể là? Có lẽ một bản cập nhật cho góc đã xảy ra? Dù sao - đó là một cách tiếp cận thanh lịch, nếu nó có thể làm việc.
domoarigato

1
nm, tôi thấy vấn đề là gì Có một lỗi đánh máy attrs.onReady, nên là như bây giờ. Vấn đề khác là tôi đã gọi nó là sôi nổi .... ... những gì tôi nhận được khi chuyển đổi coffeescript từ bộ nhớ sang JS.
jusopi

1
Tôi nghĩ trong một số trường hợp có thể ổn, nhưng lập luận của tôi chống lại nó là: Tôi nghĩ rằng những kỳ vọng về mã của anh ấy khi chỉ liếc qua là sẽ trả về một số giá trị văn bản để hiển thị trong DOM, vì nó cần một con mắt cẩn thận; Nó không cho phép bất kỳ thời điểm nào về mức độ ưu tiên chỉ thị, bạn bị kẹt ở cấp điều khiển trừ khi bạn sử dụng $timeout; Bạn rõ ràng đang tạo một addt. Nút DOM chỉ đơn giản để thực hiện logic phi dom; Nó chỉ có thể sử dụng lại nếu phương thức đó nằm xa trong hệ thống phân cấp $ phạm vi sao cho phạm vi con kế thừa nó, tôi chỉ nghĩ rằng nó trông tệ trong phối cảnh NG;
jusopi

5
Làm việc cho tôi sau khi thêm một $timeout(function() {})xung quanh elem.ready(). Nếu không, nó đã ném một $digest already in progresslỗi. Nhưng dù sao, cảm ơn rất nhiều! Tôi đã vật lộn với điều này trong một giờ qua.
rkrish Nam

1
Đào qua phạm vi $ dường như trống rỗng. Có ý kiến ​​gì không?
MiloTheGreat

66

Bạn có thể gọi nó trực tiếp bằng cách thêm vào {{YourFunction()}}sau phần tử HTML.

Đây là một Plunker Link.


6
Bạn có thể vui lòng giải thích thêm câu trả lời của bạn thêm một chút mô tả về giải pháp bạn cung cấp không?
abarisone

Tôi nghĩ rằng bạn muốn gọi một hàm khi phần tử html đó được tải. Vì vậy, gọi chức năng đó như đã đề cập ở trên. Nếu tôi đoán đúng về nghi ngờ của bạn thì điều này sẽ có tác dụng nếu không hãy giải thích câu hỏi của bạn. :)
màu xanh

14
Khi gọi một chức năng như thế này. Hãy chắc chắn rằng nó được gọi một lần hoặc nếu không thì chu trình tiêu hóa sẽ chạy vô hạn và hiển thị lỗi
Ashan

2
Tôi thích giải pháp này, nó thực sự rất đơn giản
Kamuran Sönecek

1
Điều này thật tuyệt vời - chỉ có một vấn đề. Có vẻ như chức năng của tôi chạy 5 lần khi tôi sử dụng này. Tôi đã thêm một bộ đếm để nó hoạt động tốt nhưng tôi chỉ tự hỏi liệu có ai biết tại sao điều đó sẽ xảy ra không ... Có vẻ hơi lạ bạn biết không?
itchyspacesuit

22

Tôi đã phải thực hiện logic này trong khi xử lý với các biểu đồ google. những gì tôi đã làm là vào cuối html của tôi trong định nghĩa bộ điều khiển tôi đã thêm.

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

và trong chức năng đó chỉ cần gọi logic của bạn.

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

Tôi đang sử dụng cái này nhưng ở đầu trang, init yêu cầu một số div đã được tải rồi nên bằng cách di chuyển ng-init xuống cuối trang đã khắc phục vấn đề của tôi, mẹo hay và nó có ý nghĩa.
Gurnard

chỉ có câu trả lời giúp tôi giải quyết vấn đề của mình (lựa chọn trống di động jquery)
kaiser

Đây là câu trả lời thực sự vì nó thích nghi với các điều khiển được tải động và cực kỳ dễ thực hiện.
Jason Sebring

câu trả lời này đã giúp tôi tiết kiệm thời gian, rất thanh lịch và hiệu quả cho trường hợp sử dụng của tôi
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
    };

}] );

Phương pháp trên làm việc cho tôi


3

bạn có thể gọi phiên bản javascript của sự kiện onload trong js góc. sự kiện ng-load này có thể được áp dụng cho bất kỳ phần tử dom nào như div, span, body, iframe, img, v.v. sau đây là liên kết để thêm ng-load trong dự án hiện tại của bạn.

tải ng-load cho js góc

Dưới đây là ví dụ cho iframe, một khi nó được tải testCallbackFunction sẽ được gọi trong bộ điều khiển

THÍ DỤ

Mã não

    // 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>

Vui lòng thêm một số mã ví dụ cho thấy cách OP có thể giải quyết vấn đề
JRO

@jro Cập nhật ans của tôi. Hy vọng nó sẽ hữu ích :)
Darshan Jain

2

Nếu bạn đang nhận được $ digest đang có lỗi tiến trình, điều này có thể giúp:

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

Chạy sau khi tải trang nên được thỏa mãn một phần bằng cách đặt trình lắng nghe sự kiện cho sự kiện tải cửa sổ

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

Bên trong module.run(function()...)góc cạnh, bạn sẽ có tất cả quyền truy cập vào cấu trúc mô-đun và các phụ thuộc.

Bạn có thể broadcastemit các sự kiện cho cầu nối truyền thông.

Ví dụ:

  • mô-đun thiết lập sự kiện tải và logic xây dựng
  • sự kiện phát sóng mô-đun đến bộ điều khiển khi logic yêu cầu nó
  • bộ điều khiển sẽ lắng nghe và thực hiện logic riêng dựa trên các quy trình tải mô-đun.

0

Tôi đã sử dụng {{myFunction()}}trong mẫu nhưng sau đó tìm thấy một cách khác ở đây bằng cách sử dụng $timeoutbên trong bộ điều khiển. Tôi nghĩ tôi sẽ chia sẻ nó, làm việc rất tốt cho tôi.

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();
});

}]);

Tôi đã thử tất cả các câu trả lời ở đây và vì một số lý do, $ timeout là điều duy nhất hiệu quả với tôi. Không chắc chắn tại sao, nhưng nó có thể có liên quan đến ng-gộp và thời điểm bắt đầu dịch vụ.
Drellgor

Tôi đã thêm một dấu cộng cho {{myFunction ()}}
thường gặp vào

0

Nếu bạn muốn phần tử nào đó được tải hoàn toàn, hãy sử dụng ng-init trên phần tử đó.

ví dụ <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

Hàm initModalFacemonyInfo () nên tồn tại trong bộ điều khiển.


0

Tôi thấy rằng nếu bạn có các chế độ xem lồng nhau - $ viewContentLoaded được kích hoạt cho mọi chế độ xem được lồng. Tôi đã tạo ra cách giải quyết này để tìm $ viewContentLoaded cuối cùng. Có vẻ hoạt động tốt để thiết lập $ window.prerenderReady theo yêu cầu của Prerender (đi vào .run () trong app.js chính):

// 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.");
};
});

Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
rollstuhlfahrer

0

Giải pháp phù hợp với tôi là như sau

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);
                        }
                    });
                }
            }
        }
    }
}]);

Mã điều khiển như sau

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

Mã Html là như sau

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

-31

Tôi sử dụng setIntervalđể chờ nội dung được tải. Tôi hy vọng điều này có thể giúp bạn giải quyết vấn đề đó.

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
Có phải mọi người vẫn đề nghị setIntervallà một giải pháp trong năm 2016 ?
Zachary Dahan

nhưng không có api đơn giản trong agular ... làm thế nào .. làm thế nào để làm điều đó?
Piotr Kula
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.