【问题标题】:AngularJs event to call after content is loaded加载内容后调用的 AngularJs 事件
【发布时间】:2023-04-04 09:30:02
【问题描述】:

我有一个函数,我想在加载页面内容后调用它。我阅读了有关 $viewContentLoaded 的信息,但它对我不起作用。我正在寻找类似的东西

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

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

【问题讨论】:

标签: angularjs events loaded


【解决方案1】:

根据$viewContentLoaded 的文档,它应该可以工作

每次重新加载 ngView 内容时发出。

$viewContentLoaded 事件已发出,这意味着要接收此事件,您需要一个父控制器,例如

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

MainCtrl你可以收听事件

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

查看Demo

【讨论】:

  • 这种方法的问题是控制器此时还没有完全初始化。
  • @Reza 他是对的,这个事件是在添加 dom 时触发的,但在 angular 完成处理 dom 之前。您可以通过添加一个 id 或类作为角度变量来测试它,并尝试使用 jQuery 在 $viewContentLoaded 中找到它。你不会找到它。
  • @Reza 是的,Thomas 是对的,表单元素无法在 $viewContentLoaded 中访问说,$scope.formName.elementName.$setValidity("validateRule", false);将抛出“TypeError:无法读取未定义的属性'elementName'”
  • 同样可以在 $rootScope 级别调用。而不是 $scope.$on,它应该是 $rootScope.$on 并且在 app.run() 块内
  • 当您有ng-repeat 和几个嵌套指令将根据复杂的循环和条件生成 HTML/内容时,此选项将不起作用。渲染会持续一段时间,即使在$viewContentLoaded 事件被触发之后。如何确保所有元素都已完全渲染然后执行某些代码?有什么反馈吗?
【解决方案2】:

角度

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

角度 >= 1.6.X

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

【讨论】:

  • 这是否包含在 app.js 中?
  • 你可以在你的controllers.js中收听
  • 在 app.js 主文件中也可以正常工作。
  • 这个答案对我有用!只需在文档元素页面上看到' ready() (已弃用,使用 angular.element(callback) 而不是 angular.element(document).ready(callback)) '
  • 这对我有用。接受的答案方法在控制器内部不起作用。
【解决方案3】:

已修复 - 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 方式。

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

【讨论】:

  • 这看起来是一个非常好的解决方案,但我无法让它发挥作用。它在elem.ready( $scope.$apply( readyFunc( $scope ))); 窒息,任何想法为什么会这样?也许发生了对角度的更新?无论如何 - 如果可行的话,这是一种优雅的方法。
  • nm,我明白了问题所在。 attrs.onReady 有错字,应该是现在的样子。另一个问题是我称它为时髦............我将咖啡脚本从内存转换为 JS 得到了什么。
  • 我认为在某些情况下这可能很好,但我反对它的论点是:我认为他的代码的期望只是一瞥就会返回一些文本值以显示在 DOM 中,ergo它需要仔细的眼睛;它不允许在指令优先级方面进行任何计时,除非您使用$timeout,否则您将被困在控制器级别;您正在明确创建一个 addt。 DOM 节点简单地执行非 dom 逻辑;仅当该方法位于 $scope 层次结构中很远的位置以便子作用域继承它时,它才可重用;我只是认为从 NG 的角度来看它看起来很糟糕;
  • elem.ready() 周围添加$timeout(function() {}) 后为我工作。否则它会抛出 $digest already in progress 错误。但无论如何,非常感谢!在过去的一个小时里,我一直在为此苦苦挣扎。
  • 挖掘 $scope 似乎是空的。有什么想法吗?
【解决方案4】:

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

这是Plunker Link

【讨论】:

  • 能否请您详细说明您的答案,添加更多关于您提供的解决方案的描述?
  • 调用这样的函数时。确保它被调用一次,否则摘要循环将无限运行并显示错误
  • 我喜欢这个解决方案,真的很简单
  • 这太棒了——只有一个问题。当我使用它时,我的函数似乎运行了 5 次。我添加了一个计数器,所以它工作正常,但我只是想知道是否有人知道为什么会发生这种情况......你知道看起来有点奇怪吗?
  • 这会导致无限循环,不应使用。使用&lt;div ng-init="yourFuction()"&gt;&lt;/div&gt;,如Saad's answer所示
【解决方案5】:

我必须在处理谷歌图表时实现这个逻辑。我所做的是在我添加的控制器定义中的 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 empty selection)
  • 这是真正的答案,因为它适应动态加载的控件并且非常容易实现。
  • 这个答案为我节省了一些时间,对我的用例来说如此优雅和有效
【解决方案6】:
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
    };

}] );

以上方法对我有用

【讨论】:

    【解决方案7】:

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

    download ng-load for 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 更新了我的回答。希望它会有所帮助:)
    【解决方案8】:

    如果您收到 $digest already in progress 错误,这可能会有所帮助:

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

    【讨论】:

      【解决方案9】:

      我在模板中使用了{{myFunction()}},但后来在控制器中使用$timeout 找到了另一种方式here。想我会分享它,对我很有用。

      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 和启动服务的时间有关。
      • 我为 {{myFunction()}} 加了一个
      【解决方案10】:

      在页面加载后运行应该通过为窗口加载事件设置一个事件监听器来部分满足

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

      在 angular 的 module.run(function()...) 中,您将拥有对模块结构和依赖项的所有访问权限。

      您可以使用broadcastemit 事件进行通信桥接。

      例如:

      • 模块设置加载事件和构建逻辑
      • 模块在逻辑需要时向控制器广播事件
      • 控制器将根据模块加载过程监听并执行自己的逻辑。

      【讨论】:

        【解决方案11】:

        如果您希望某个元素完全加载,请在该元素上使用 ng-init。

        例如&lt;div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"&gt; ..&lt;/div&gt;

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

        【讨论】:

          【解决方案12】:

          我发现如果您有嵌套视图 - 每个嵌套视图都会触发 $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 ++;
          });
          

          【讨论】:

            【解决方案13】:
            var myTestApp = angular.module("myTestApp", []); 
            myTestApp.controller("myTestController", function($scope, $window) {
            $window.onload = function() {
             alert("is called on page load.");
            };
            });
            

            【讨论】:

            • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
            【解决方案14】:

            对我有用的解决方案如下

            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()">
            

            【讨论】:

              【解决方案15】:

              我使用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);
              

              【讨论】:

              • 人们仍然推荐setInterval作为2016的解决方案吗?
              • 但是在 agular 中没有简单的 api... 怎么 .. 怎么做?
              猜你喜欢
              • 2019-03-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多