如何在页面加载时执行AngularJS控制器功能?


359

目前,我有一个Angular.js页面,它允许搜索并显示结果。用户单击搜索结果,然后单击“后退”按钮。我希望再次显示搜索结果,但是我不知道如何触发搜索执行。这是细节:

  • 我的Angular.js页面是一个搜索页面,带有一个搜索字段和一个搜索按钮。用户可以手动键入查询并按下按钮,然后会触发ajax查询并显示结果。我用搜索词更新了网址。一切正常。
  • 用户单击搜索结果,然后转到另一个页面-效果也不错。
  • 用户单击“后退”按钮,然后返回到我的角度搜索页面,并显示正确的URL(包括搜索词)。一切正常。
  • 我已将搜索字段值绑定到URL中的搜索词,因此它包含了预期的搜索词。一切正常。

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


你在用$routepProvider吗?使用它连接到您的应用程序中的服务,该服务为搜索结果提供数据。不要document.ready像使用jQuery 那样来思考。在不掌握当前搜索方式的情况下很难提供很多帮助
charlietfl 2013年

Answers:


430

一方面,如@ 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
};

但是要小心,因为角度文档暗示(自v1.2起)不要ng-init为此使用。但是imo取决于您应用程序的体系结构。

ng-init当我想将后端的值传递到有角度的应用程序时,我用过:

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

6
@Duke,您不能只是将init()函数的内容放在控制器的底部吗?即,为什么需要使用ng-init并具有init()函数?当用户单击后退按钮时,我假设您正在切换视图,因此将myCtrl创建并执行一个新的控制器。
Mark Rajcok

24
尽管此解决方案有效,但我拒绝投票,因为ng-init文档建议不要这样做。具体来说,“如下面的演示所示,只有将ngInit用作ngRepeat特殊属性的别名。除此之外,您应该使用控制器而不是ngInit来初始化作用域上的值。”
杰森·卡普里奥蒂

1
在html放置好之后,实例化控制器。
Dmitry Evseev 2014年

3
如果控制器在其他页面中重复使用,但您只想在特定页面上触发该怎么办?
罗伯托·利纳雷斯

3
@RobertoLinares我个人认为指令是可重用功能的更好场所。您可以使用带有init参数的指令<div smth on-init="doWhatever()">。当然,这取决于特定的使用情况。
德米特里Evseev 2014年

135

尝试这个?

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

5
感谢您的答复,但德米特里(Dmitry)的答案与我所寻找的完全匹配。进一步的研究似乎建议反对$ viewContentLoaded
杜加尔·杜加尔

7
用例只是不同。我也一直使用Mark的方法。
全息原理

对于我的用例,这是一个完美的解决方案。我们需要自动选择文本以鼓励用户复制它。该页面可以多次重新加载/重新访问,因此$ viewContentLoaded是完全匹配的。谢谢!
Olga Gnatenko

是否有可能执行多次?我得到的行为似乎正在模仿……
MadPhysicist '16

1
这对我不起作用,但是$ scope。$ watch有效。主要区别是什么?
Burak Tokak '16

59

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

这是我的工作,对我有用:

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

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

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

1
你真棒,我的朋友。
塔科2015年

正是我所需要的。我真的在找这两天!
hellojebus

3
$scope.$on('$routeChangeSuccess'每当url中的参数更改时都会触发($location例如通过),因此您可以使用just $scope.$on('$locationChangeSuccess'。如果在页面加载/重新加载时需要一些触发器,则可以$scope.$watch('$viewContentLoaded'按此处建议的那样使用。网址参数更改期间不会触发。
Neurotransmitter

使用AngularJS 1.17.2,内部控制器$ routeChangeSuccess发挥了惊人的作用……adam0101万岁...
ArifMustafa

43
angular.element(document).ready(function () {

    // your code here

});

4
必须是公认的答案,这是更安全的方法
Marwen Trabelsi

如果我们不使用$scope而是使用,这很好this
阿卡什(Akash)

这需要去哪里?我的模板中有它,但它没有触发。
戴夫

在这种情况下,不是最好注入$ document吗?angular.element($ document).ready ...
jamie

4
解释将不胜感激
Hidayt Rahman

32

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

# Your controller, including $timeout

var $scope.init = function(){
 //your code
}

$timeout($scope.init)

希望能帮助到你。


3
最后。这是唯一为我工作的人。谢谢。
zmirc

1
这可行。也不要忘记使用$ timeout.cancel(timer)清除超时,其中var timer = $ timeout($ scope.init,ms);初始化完成后。另外,我不认为$ scope在上面的代码中应该有一个'var'def
Emmanuel NK

这应该是公认的答案。这是唯一为我工作的人(尝试了以上所有答案)。如果您正在等待加载iframe,它甚至可以工作。
hello_fr1end

这有效!viewcontentLoaded对我不起作用
黑暗骑士

28

如果要观看viewContentLoaded DOM对象进行更改,然后执行某些操作,则可以执行此操作。使用$ scope。$ on也可以,但是有所不同,特别是当您在路由上使用一页模式时。

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

7
具体来说,如果您使用$ rootScope。$ watch而不是$ rootScope。$ on,则它不会在路由更改时触发,因此您可以使用特定于初始页面加载的逻辑。
csahlman 2014年

19

您可以使用angular的$ window对象:

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


3

如果您有一个仅针对该页面的控制器,则还有另一种选择:

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

3

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

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

3

发现Dmitry Evseev的答案很有用。

情况1:单独使用angularJs:
要在页面加载时执行方法,您可以ng-init在视图中使用并在controller中声明init方法,但根据ng-init上angular Docs的建议,建议不要使用更重的功能:

可以滥用此伪指令在模板中添加不必要的逻辑量。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.jsas中禁用了视图缓存:

route.js

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

希望这可以帮助


1
它只有一个向上,并位于最底部,很高兴我一直走下去,cache: false为我做到了–谢谢!
拉尼·凯尔

3

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

angular.element(window.document.body).ready(function () {

                        // Your function that runs after all DOM is loaded

                    });

2

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

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

为您的后退按钮

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

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.