加载内容后要调用的AngularJs事件


163

我有一个要在页面内容加载后调用的函数。我读到有关$ viewContentLoaded的内容,但对我来说不起作用。我正在寻找类似的东西

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

在AngularJs控制器中,上述调用对我不起作用。


Answers:


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或类添加为角度变量来进行测试,并尝试在jQuery的$ viewContentLoaded中找到它。您将找不到它。
Thomas Kekeisen

1
@Reza是的,Thomas是对的,表单元素无法在$ viewContentLoaded内部访问,例如,$ scope.formName.elementName。$ setValidity(“ validateRule”,false); 将抛出“ TypeError:无法读取未定义的属性'elementName'”
Mussammil 2015年

2
可以在$ rootScope级别上调用相同的命令。而不是$ scope。$ on,它应该是$ rootScope。$ on并位于app.run()块内部
Vil

4
当您有ng-repeat多个嵌套指令将根据复杂的循环和条件生成HTML / Content 时,此选项将不起作用。即使$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 '16

3
您可以在controllers.js中收听它
hariszaman

2
在主app.js文件中也可以正常工作。
Loubot

这个答案对我有用!只需在文档元素页面上看到'ready()(已弃用,请使用angular.element(callback)而不是angular.element(document).ready(callback))'
Lovera

这对我有用。可接受的答案方法不适用于控制器内部。
法比亚诺

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>

或对于那些使用controller-as语法的人...

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

这样做的好处是您可以随心所欲地使用UI进行宽泛或细化,并从控制器中删除DOM逻辑。我认为这是推荐的Angular方法。

如果其他指令在同一节点上运行,则可能需要优先考虑此指令。


这看起来是一个非常好的解决方案,但是我无法使其正常工作。它cho不休,elem.ready( $scope.$apply( readyFunc( $scope ))); 为什么会这样呢?也许对角度的更新发生了?无论如何-如果可行的话,这是一种优雅的方法。
domoarigato

1
nm,我明白了问题所在。上有一个错字attrs.onReady,应该是现在的错字。另一个问题是我称之为时髦。。。。。。。。。。。。。。。
jusopi 2015年

1
我认为在某些情况下可能会很好,但我对此表示反对:我认为,只要瞥一眼他的代码的期望便是返回一些文本值以显示在DOM中。它不允许在指令优先级方面进行任何计时,除非您使用$timeout; 否则您就陷于控制器级别。您正在显式创建addt。DOM节点只是执行非dom逻辑;仅当该方法位于$ scope层次结构中的较高位置以使子作用域继承该方法时,它才可重用;我只是认为从NG角度看,它看起来很糟糕;
jusopi 2015年

5
$timeout(function() {})周围添加了字词后为我工作elem.ready()。否则,它将引发$digest already in progress错误。但是无论如何,非常感谢!在过去的一个小时里,我一直在为此苦苦挣扎。
rkrishnan '16

1
通过$ scope挖掘似乎是空的。有任何想法吗?
MiloTheGreat,2016年

66

您可以通过{{YourFunction()}}在HTML元素后添加直接调用它。

这是一个Plunker Link


6
您能否详细说明您的答案,并提供有关您提供的解决方案的更多说明?
abarisone 2015年

我认为您想在加载html元素时调用一个函数。因此,请如上所述调用该函数。如果我的猜测对您的疑问是正确的,那么这将起作用,否则请详细说明您的问题。:)
蓝色

14
当调用这样的函数时。确保其被调用一次,否则摘要循环将无限运行并显示错误
Ashan

2
我喜欢这个解决方案,它真的是如此简单
KamuranSönecek2015年

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移至页面底部可以解决我的问题,这是很好的提示,这很有意义。
古纳德

唯一可以帮助我解决我的问题的答案(jQuery Mobile空选择)
kaiser

这是真正的答案,因为它适用于动态加载的控件,并且超级易于实现。
詹森·塞布林

这个答案为我节省了一些时间,对我的用例而言如此优雅而有效
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

您可以在angular js中调用onload事件的javascript版本。此ng-load事件可应用于任何dom元素,例如div,span,body,iframe,img等。以下是在现有项目中添加ng-load的链接。

下载angular-js的ng-load

以下是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,5:54

@jro更新了我的回答。希望对您有所帮助:)
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()...)angular的内部,您将有权访问模块的结构和相关性。

您可以broadcastemit事件建立通信桥梁。

例如:

  • 模块设置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();
});

}]);

我在这里尝试了所有答案,由于某种原因,$ timeout是唯一对我有用的东西。不知道为什么,但是可能与ng-include和启动服务的时间有关。
Drellgor '17

我为{{myFunction()}}添加了一个加号
commonpike,

0

如果要完全加载某些元素,请对该元素使用ng-init。

例如 <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

initModalFacultyInfo()函数应存在于控制器中。


0

我发现,如果您具有嵌套视图,则每个嵌套视图都会触发$ viewContentLoaded。我已创建此替代方法来查找最终的$ viewContentLoaded。似乎可以按照Prerender的要求设置$ window.prerenderReady正常工作(进入主app.js中的.run()):

// 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
人们setInterval2016年仍会推荐作为解决方案吗?
Zachary Dahan

但是敏捷中没有简单的api ...如何..怎么做?
Piotr Kula
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.