【问题标题】:How to execute AngularJS controller function on page load?如何在页面加载时执行 AngularJS 控制器功能?
【发布时间】:2013-03-05 17:08:34
【问题描述】:

目前我有一个允许搜索和显示结果的 Angular.js 页面。用户单击搜索结果,然后单击返回按钮。我希望再次显示搜索结果,但我不知道如何触发搜索执行。详情如下:

  • 我的 Angular.js 页面是一个搜索页面,有一个搜索字段和一个搜索 按钮。用户可以手动输入查询并按下按钮 并触发 ajax 查询并显示结果。我用搜索词更新 URL。一切正常。
  • 用户点击搜索结果并被带到另一个页面 - 这也很好。
  • 用户单击返回按钮,返回我的角度搜索页面,并显示正确的 URL,包括搜索词。一切正常。
  • 我已将搜索字段值绑定到 URL 中的搜索词,因此它包含预期的搜索词。一切正常。

如何在不让用户按下“搜索按钮”的情况下再次执行搜索功能?如果是 jquery,那么我将在 documentready 函数中执行一个函数。我看不到 Angular.js 等效项。

【问题讨论】:

  • 你在使用$routepProvider吗?使用它连接到应用程序中为搜索结果提供数据的服务。不要像 jQuery 那样用document.ready 术语来思考。如果不了解您当前如何连接搜索,很难提供很多帮助

标签: angularjs onload


【解决方案1】:

在自初始化函数中调用初始方法。

(function initController() {

    // do your initialize here

})();

【讨论】:

    【解决方案2】:

    您可以将搜索结果保存在一个通用服务中,该服务可以在任何地方使用,并且导航到另一个页面时不会清除,然后您可以使用保存的数据设置搜索结果,以便单击返回按钮

    function search(searchTerm) {
        // retrieve the data here;
        RetrievedData = CallService();
        CommonFunctionalityService.saveSerachResults(RetrievedData);
    } 
    

    为您的后退按钮

    function Backbutton() {
        RetrievedData = CommonFunctionalityService.retrieveResults();
    }
    

    【讨论】:

      【解决方案3】:

      我永远无法让$viewContentLoaded 为我工作,ng-init 真的应该只在ng-repeat 中使用(根据文档),并且如果直接在控制器中调用函数也会导致错误代码依赖于尚未定义的元素。

      这就是我所做的,它对我有用:

      $scope.$on('$routeChangeSuccess', function () {
        // do something
      });
      

      除非您使用的是ui-router。然后是:

      $scope.$on('$stateChangeSuccess', function () {
        // do something
      });
      

      【讨论】:

      • 你太棒了,我的朋友。
      • 正是我需要的。我真的在找这个两天!
      • $scope.$on('$routeChangeSuccess' 每次更改 url 中的参数时触发(例如通过$location),因此您可以只使用$scope.$on('$locationChangeSuccess'。如果您在页面加载/重新加载时需要一些触发器,您可以按照此处的建议使用$scope.$watch('$viewContentLoaded'。它不会在 url 参数更改期间触发。
      • 使用 AngularJS 1.17.2,在控制器 $routeChangeSuccess 内部工作得非常好……adam0101 万岁……
      【解决方案4】:

      我遇到了同样的问题,只有这个解决方案对我有用(它在加载完整的 DOM 后运行一个函数)。我在页面加载后使用它来滚动锚点:

      angular.element(window.document.body).ready(function () {
      
                              // Your function that runs after all DOM is loaded
      
                          });
      

      【讨论】:

        【解决方案5】:

        你可以使用 Angular 的 $window 对象:

        $window.onload = function(e) {
          //your magic here
        }
        

        【讨论】:

          【解决方案6】:

          发现 Dmitry Evseev 的答案非常有用。

          案例1:单独使用angularJs:
          要在页面加载时执行方法,您可以在视图中使用ng-init,并在控制器中声明init方法,但根据angular Docs on ng-init,不建议使用较重的函数:

          可以滥用该指令在模板中添加不必要的逻辑。 ngInit 只有少数合适的用途,例如用于别名 ngRepeat 的特殊属性,如下面的演示所示;以及通过服务器端脚本注入数据。除了这几种情况,您应该使用控制器而不是 ngInit 来初始化作用域上的值。

          HTML:

          <div ng-controller="searchController()">
              <!-- renaming view code here, including the search box and the buttons -->
          </div>
          

          控制器:

          app.controller('SearchCtrl', function(){
          
              var doSearch = function(keyword){
                  //Search code here
              }
          
              doSearch($routeParams.searchKeyword);
          })
          

          警告:不要将此控制器用于另一个意图不同的视图,因为它会导致搜索方法也在那里执行。

          案例 2:使用 Ionic:
          上面的代码可以工作,只要确保route.js中的视图缓存被禁用:

          route.js

          .state('app', {
              url           : '/search',
              cache         : false, //disable caching of the view here
              templateUrl   : 'templates/search.html'   ,
              controller    : 'SearchCtrl'
            })
          

          希望对你有帮助

          【讨论】:

          • 这只有一个,在最底部,很高兴我一路下降,cache: false 为我做了 - 谢谢!
          【解决方案7】:

          使用 $routeProvider 时,您可以解析 .state 并引导您的服务。这就是说,你要加载 Controller 和 View,只有在解决你的 Service 之后:

          ui-路由

           .state('nn', {
                  url: "/nn",
                  templateUrl: "views/home/n.html",
                  controller: 'nnCtrl',
                  resolve: {
                    initialised: function (ourBootstrapService, $q) {
          
                      var deferred = $q.defer();
          
                      ourBootstrapService.init().then(function(initialised) {
                        deferred.resolve(initialised);
                      });
                      return deferred.promise;
                    }
                  }
                })
          

          服务

          function ourBootstrapService() {
          
           function init(){ 
              // this is what we need
           }
          }
          

          【讨论】:

            【解决方案8】:

            如果您有一个特定于该页面的控制器,还有另一种选择:

            (function(){
                //code to run
            }());
            

            【讨论】:

              【解决方案9】:
              angular.element(document).ready(function () {
              
                  // your code here
              
              });
              

              【讨论】:

              • 必须是公认的答案,这是更安全的方法
              • 如果我们不使用$scope,而是使用this,这很好。
              • 这需要去哪里?我的模板中有它,但它没有触发。
              • 在这种情况下注入 $document 不是最好的吗? angular.element($document).ready...
              • 解释将不胜感激
              【解决方案10】:

              另一种选择:

              var myInit = function () {
                  //...
              };
              angular.element(document).ready(myInit);
              

              (通过https://stackoverflow.com/a/30258904/148412

              【讨论】:

                【解决方案11】:

                Dimitri 的/Mark 的解决方案对我不起作用,但使用 $timeout 函数似乎可以很好地确保您的代码仅在呈现标记后运行。

                # Your controller, including $timeout
                
                var $scope.init = function(){
                 //your code
                }
                
                $timeout($scope.init)
                

                希望对你有帮助。

                【讨论】:

                • 最后。这是唯一对我有用的。谢谢。
                • 这行得通。也不要忘记用 $timeout.cancel(timer) 清除超时,你有 var timer = $timeout($scope.init, milliseconds);一旦你的初始化完成。另外,我认为 $scope 上面的代码中不应包含“var”定义
                • 这应该是公认的答案。这是唯一对我有用的(尝试了上面的所有答案)。如果您正在等待 iframe 加载,它甚至可以工作。
                【解决方案12】:

                如果你想观察 viewContentLoaded DOM 对象的变化然后做一些事情,你可以这样做。使用 $scope.$on 也有效,但不同的是,尤其是当您在路由上使用一页模式时。

                 $scope.$watch('$viewContentLoaded', function(){
                    // do something
                 });
                

                【讨论】:

                • 具体来说,如果您使用 $rootScope.$watch 而不是 $rootScope.$on 它不会在路由更改时触发,因此您可以使用特定于初始页面加载的逻辑。
                【解决方案13】:

                一方面正如@Mark-Rajcok 所说,您可以摆脱私有内部函数:

                // at the bottom of your controller
                var init = function () {
                   // check if there is query in url
                   // and fire search in case its value is not empty
                };
                // and fire it after definition
                init();
                

                您还可以查看ng-init 指令。实现将很像:

                // register controller in html
                <div data-ng-controller="myCtrl" data-ng-init="init()"></div>
                
                // in controller
                $scope.init = function () {
                    // check if there is query in url
                    // and fire search in case its value is not empty
                };
                

                但请注意angular documentation implies (since v1.2),不要为此使用ng-init。但是,imo 这取决于您的应用程序的架构。

                当我想将值从后端传递到 Angular 应用程序时,我使用了 ng-init

                <div data-ng-controller="myCtrl" data-ng-init="init('%some_backend_value%')"></div>
                

                【讨论】:

                • @Duke,你不能把 init() 函数的内容放在控制器的底部吗?即,为什么需要使用 ng-init 并具有 init() 函数?当用户点击后退按钮时,我假设您正在切换视图,因此会创建并执行一个新的 myCtrl 控制器。
                • 虽然这个解决方案有效,但我投了反对票,因为 ng-init 文档不建议这样做。具体来说,“ngInit 的唯一适当用途是对 ngRepeat 的特殊属性进行别名化,如下面的演示所示。除了这种情况,您应该使用控制器而不是 ngInit 来初始化作用域上的值。”
                • 控制器在 html 就位后被实例化。
                • 如果控制器在其他页面中重复使用但您只想在特定页面上触发它怎么办?
                • @RobertoLinares 我个人认为指令是可重用功能的更好地方。您可以使用带有 init 参数的指令:&lt;div smth on-init="doWhatever()"&gt;。当然,这取决于特定的用例。
                【解决方案14】:

                试试这个?

                $scope.$on('$viewContentLoaded', function() {
                    //call it here
                });
                

                【讨论】:

                • 感谢您的回复,但 Dmitry 的回答与我正在寻找的完全匹配。进一步的研究似乎建议反对 $viewContentLoaded
                • 用例只是不同而已。我也一直使用马克的方法。
                • 对于我的用例来说,这是一个完美的解决方案。我们需要自动选择文本以鼓励用户复制它。该页面可以多次重新加载/重新访问,因此 $viewContentLoaded 是完全匹配的。谢谢!
                • 这可能会执行多次吗?我的行为似乎在模仿...
                • 这个对我不起作用,但 $scope.$watch 起作用了。主要区别是什么?
                猜你喜欢
                • 2016-04-03
                • 2017-01-12
                • 2016-08-21
                • 1970-01-01
                • 1970-01-01
                • 2016-09-20
                • 2012-12-18
                • 1970-01-01
                • 2014-10-25
                相关资源
                最近更新 更多