对抗AngularJS执行控制器两次

我知道AngularJS会将一些代码运行两次,有时甚至更多,比如$watch事件,不断检查模型状态等等。

然而我的代码:

function MyController($scope, User, local) {


var $scope.User = local.get(); // Get locally save user data


User.get({ id: $scope.User._id.$oid }, function(user) {
$scope.User = new User(user);
local.save($scope.User);
});


//...

执行两次,将2条记录插入到我的DB中。我显然还在学习,因为我已经用我的头撞它很多年了!

173621 次浏览

应用路由器指定导航到MyController,如下所示:

$routeProvider.when('/',
{ templateUrl: 'pages/home.html',
controller: MyController });

但我在home.html中也有这个:

<div data-ng-controller="MyController">

这对控制器进行了两次消化。从HTML中删除data-ng-controller属性解决了这个问题。或者,controller:属性可以从路由指令中删除。

使用选项卡导航时也会出现此问题。例如,app.js可能包含:

  .state('tab.reports', {
url: '/reports',
views: {
'tab-reports': {
templateUrl: 'templates/tab-reports.html',
controller: 'ReportsCtrl'
}
}
})

相应的报告标签HTML可能类似于:

<ion-view view-title="Reports">
<ion-content ng-controller="ReportsCtrl">

这也将导致运行控制器两次。

如果你知道你的控制器无意中执行了不止一次,试着在你的文件中搜索有问题的控制器的名称,例如:search: MyController在所有文件中。很可能它被复制粘贴到其他html/js文件中,当你开发或使用这些部分/控制器时忘记更改它。来源:我犯了这个错误

< p > # EYZ0 < br > 注意,还可以通过声明DOM将控制器附加到DOM 在路由定义中通过$route服务。一个常见的错误是to 在模板中使用ng-controller再次声明控制器 本身。这将导致控制器被附加并执行 两次。< /强> < / p >

当你在ng-view指令中使用ngRoute时,控制器默认会附加到那个dom元素(如果你使用ui-router,则会附加到ui-view)。因此,您不需要在模板中再次附加它。

特此补充,以供参考:

在同样运行在页面上的指令中引用控制器也可能导致双控制器代码执行。

如。

return {


restrict: 'A',
controller: 'myController',
link: function ($scope) { ....

当你也有ng-controller="myController"在你的HTML

只是想再添加一个控制器可以init两次的情况(这是实际的angular.js 1.3.1):

<div ng-if="loading">Loading...</div>
<div ng-if="!loading">
<div ng-view></div>
</div>

在本例中为$route。ng-view初始化时,Current已经设置。会导致双重初始化。

要修复它,只需将ng-if更改为ng-show/ng-hide,一切都将正常工作。

在某些情况下,当你没有像这样纠正close you指令时,你的指令会运行两次:

# EYZ0

这将运行你的指令两次。 还有另一种情况,当你的指令运行两次:

确保你没有在index.html 两次中包含你的指令!

我有同样的问题,在一个简单的应用程序(没有路由和一个简单的ng-controller引用),我的控制器的构造函数运行了两次。最后,我发现我的问题是以下声明自动引导我的AngularJS应用程序在我的Razor视图

<html ng-app="mTest1">

我还使用angular手动引导它。引导。

angular.bootstrap(document, [this.app.name]);

所以去掉其中一个,对我有用。

我刚刚讲过这个问题,但这个问题与公认的答案不同。我真的要把这些留给未来的自己,包括我为解决这个问题所采取的步骤。

  1. 删除冗余控制器声明
  2. 检查路由中后面的斜杠
  3. 检查ng-ifs
  4. 检查任何不必要的包装ng-view调用(我不小心在一个ng-view是包装我的实际ng-view。这导致我对控制器进行了三次调用。)
  5. 如果你是在Rails上,你应该从你的application.js文件中删除turbolinks宝石。我浪费了一整天才发现这一点。找到答案在这里
  6. 使用ng-app和bootstrap初始化应用程序两次。# EYZ0
  7. 当对'link'中的整个元素使用$compile时,指令的函数也定义了自己的控制器,并通过ng-click等在模板中使用该控制器的回调。找到答案在这里

当在Angular 1.3+中使用angular-ui-router时,在路由转换时渲染两次视图出现了一个问题。这也导致执行了两次控制器。提出的解决方案没有一个对我有效。

但是,将angular-ui-router从0.2.11更新到0.2.13解决了我的问题。

我把我的应用程序和它所有的依赖都撕裂了这个问题(详细信息在这里:AngularJS应用程序启动两次(尝试了通常的解决方案..))

最后,这都是巴塔朗Chrome插件的错。

这个答案分辨率:

.

我强烈建议大家在修改代码之前先禁用每一篇文章。

在我的例子中,这是因为我使用的url模式

我的url是/ui/project/:parameter1/:parameter2。

我不需要在所有状态改变的情况下都使用paramerter2。在我不需要第二个参数的情况下,我的url将像/ui/project/:parameter1/。所以每当我有状态改变时,我都会刷新控制器两次。

解决方案是将parameter2设置为空字符串并进行状态更改。

我一直在用AngularJS 1.4 rc构建这个问题,然后意识到上面的答案都不适用,因为在撰写本文时它起源于Angular 1.4和Angular 2的新路由器库。因此,我要在这里提醒那些可能正在使用新的Angular路由库的人。

基本上,如果一个html页面包含一个ng-viewport指令,用于加载应用程序的某些部分,通过单击ng-link中指定的超链接,将导致相关组件的目标控制器被加载两次。细微的区别在于,如果浏览器已经加载了目标控制器,那么重新单击相同的超链接只会调用该控制器一次。

还没有找到可行的解决方案,尽管我相信这种行为与shaunxu所提出的观察是一致的,希望这个问题能在未来的新路由库构建中以及AngularJS 1.4版本中得到解决。

在我的例子中,我发现使用相同控制器的两个视图。

$stateProvider.state('app', {
url: '',
views: {
"viewOne@app": {
controller: 'CtrlOne as CtrlOne',
templateUrl: 'main/one.tpl.html'
},
"viewTwo@app": {
controller: 'CtrlOne as CtrlOne',
templateUrl: 'main/two.tpl.html'
}
}
});

由于不同的原因,我已经有了这个双重初始化。对于我的应用程序中的一些路由转换,我想强制滚动到接近页面顶部(例如在分页搜索结果中……)单击next会将您带到第2页的顶部)。

我通过向执行的$rootScope $on $viewContentLoaded添加一个侦听器来实现这一点(基于某些条件)

$location.hash('top');

无意中,这导致我的路由被重新评估,控制器被重新初始化

我遇到的问题可能是切题的,但由于谷歌让我想到了这个问题,这可能是合适的。当我使用UI Router时,只有在我尝试用浏览器刷新按钮刷新页面时,才会出现这个问题。应用程序使用带有父抽象状态的uirouter,然后是父状态下的子状态。在应用程序run()函数中,有一个$state.go('...child-state...')命令。父状态使用resolve,起初我以为可能是子控制器执行了两次。

在URL附加散列之前一切正常 # EYZ0 < / p > 然后,一旦url被UI路由器修改,
# EYZ0 < / p >

...然后当我使用浏览器刷新按钮刷新页面时,$stateChangeStart发射两次,每次都指向childstate

父状态上的resolve是触发两次的。

也许这只是一种拼凑;无论如何,这似乎消除了我的问题:在第一次调用$stateProvider的代码区域,第一个检查window.location.hash是否为空字符串。如果是,一切都好;如果不是,那么将window.location.hash设置为空字符串。看来$state只会去一次而不是两次。

此外,如果你不想依赖应用程序的默认runstate.go(...),你可以尝试捕获哈希值,并使用哈希值来确定页面刷新前你所处的子状态,并在代码中设置state.go(...)的区域添加一个条件。

我有同样的问题,在尝试了所有的答案后,我终于发现我在我的视图中有一个指令,绑定到相同的控制器。

APP.directive('MyDirective', function() {
return {
restrict: 'AE',
scope: {},
templateUrl: '../views/quiz.html',
controller: 'ShowClassController'
}
});

删除指令后,控制器停止被调用两次。现在我的问题是,如何使用这个绑定到控制器作用域的指令而不出现这个问题?

我的问题是更新搜索参数,如$location.search('param', key);

你可以在这里阅读更多信息

控制器被调用两次,由于附加参数在url

我刚刚解决了我的问题,其实很令人失望。这是一个离子混合应用程序,我使用ui-router v0.2.13。在我的例子中,有一个epub阅读器(使用epub.js),一旦我导航到我的图书馆并选择任何其他书籍,它就会连续报告“没有找到文档”。当我重新加载浏览器的书被完美地渲染,但当我选择另一本书得到同样的问题再次。

我的解决方法很简单。我刚刚删除了reload:true$state.go("app.reader", { fileName: fn, reload: true });在我的LibraryController

我发现我的被调用两次是因为我从我的html调用了两次方法。

`<form class="form-horizontal" name="x" ng-submit="findX() novalidate >
<input type="text"....>
<input type="text"....>
<input type="text"....>
<button type="submit" class="btn btn-sm btn-primary" ng-click="findX()"
</form>`

突出显示的部分导致两次调用findX()。希望它能帮助到别人。

在我的例子中,重命名控制器为不同的名称解决了问题。

我将我的控制器从“CatalogerTreeController”重命名为“TreeController”,然后这个控制器开始在“ui树”指令使用的页面上启动两次,因为这个指令使用名为“TreeController”的控制器。

我有同样的问题在angular-route@1.6.7,这是因为额外的削减在regex路由结束:

.when('/goods/publish/:classId/', option)

.when('/goods/publish/:classId', option)

而且工作正常。

对于那些使用ControllerAs语法的人,只需在$routeprovider中声明控制器标签,如下所示:

$routeprovider
.when('/link', {
templateUrl: 'templateUrl',
controller: 'UploadsController as ctrl'
})

$routeprovider
.when('/link', {
templateUrl: 'templateUrl',
controller: 'UploadsController'
controllerAs: 'ctrl'
})

在声明了$routeprovider之后,不要像视图中那样提供控制器。相反,在视图中使用标签。

在这里加上我的案例:

我使用angular-ui-router$state.go('new_state', {foo: "foo@bar"})

一旦我将encodeURIComponent添加到参数中,问题就消失了:$state.go('new_state', {foo: encodeURIComponent("foo@bar")})

< p >发生了什么事? 参数值中的“@”字符不允许出现在url中。因此,angular-ui-router创建了我的控制器两次:在第一次创建时,它传递了原始的“foo@bar”,在第二次创建时,它将传递编码版本“foo%40bar”。一旦我像上面那样显式地对参数进行编码,问题就消失了

我的问题真的很难找到。最后,当网页缺少图像时,问题就出现了。src缺少一个Url。这发生在MVC 5 Web控制器上。为了解决这个问题,当没有真实图像可用时,我添加了透明图像。

<img alt="" class="logo" src="">