537

我了解 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 条记录插入我的数据库。我显然仍在学习,因为我多年来一直在努力解决这个问题!

4

24 回答 24

1054

应用路由器将导航指定为MyController

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

但我也有这个home.html

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

这消化了控制器两次。data-ng-controller从 HTML 中删除属性解决了这个问题。或者,该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">

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

于 2013-03-20T22:08:26.263 回答
129

AngularJS docs - ngController
请注意,您还可以通过 $route 服务在路由定义中声明控制器来将控制器附加到 DOM。一个常见的错误是在模板本身中使用 ng-controller 再次声明控制器。这将导致控制器被附加并执行两次。

当您将 ngRoute 与ng-view指令一起使用时,控制器默认附加到该 dom 元素(如果您使用 ui-router,则附加到 ui-view)。因此,您无需在模板中再次附加它。

于 2014-10-02T08:46:50.630 回答
70

我刚刚经历了这个,但问题与接受的答案不同。我真的要把它留在这里,为了我未来的自己,包括我修复它所经历的步骤。

  1. 删除多余的控制器声明
  2. 检查路线中的尾随斜杠
  3. 检查ng-ifs
  4. 检查是否有任何不必要的包装ng-view调用(我不小心留下了一个ng-view包装我实际ng-view的 . 这导致对我的控制器的三个调用。)
  5. 如果你在 Rails 上,你应该从你的文件中删除turbolinksgem 。application.js我浪费了一整天的时间来发现这一点。在这里找到答案。
  6. 使用 ng-app 和 bootstrap 初始化应用程序两次。对抗AngularJS执行控制器两次
  7. 在指令的“链接”功能中对整个元素使用 $compile 时,该指令还定义了自己的控制器,并通过 ng-click 等在模板中使用此控制器的回调。在这里找到答案。
于 2015-03-24T18:52:00.243 回答
14

只想在控制器可以初始化两次时再添加一种情况(这对于 angular.js 1.3.1 来说是实际的):

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

在这种情况下,$route.current 将在 ng-view 初始化时设置。这会导致双重初始化。

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

于 2014-11-17T11:08:58.260 回答
7

想补充以供参考:

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

例如

return {

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

当您的 HTML 中也有 ng-controller="myController" 时

于 2014-10-28T18:19:21.337 回答
7

在 Angular 1.3+ 中使用angular-ui-router时,存在关于在 route transition 上渲染视图两次的问题。这也导致两次执行控制器。建议的解决方案都不适合我。

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

于 2015-04-19T11:25:14.127 回答
6

我撕毁了我的应用程序及其所有依赖项,以解决这个问题(详细信息:AngularJS 应用程序启动两次(尝试了通常的解决方案..)

最后,这都是 Batarang Chrome 插件的错。

此答案中的分辨率:

我强烈建议任何人列表中的第一件事是在更改代码之前根据帖子禁用它。

于 2015-05-07T08:56:34.137 回答
5

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

于 2014-08-01T22:49:28.147 回答
5

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

<html ng-app="mTest1">

我还使用 angular.bootstrap 手动引导它,即

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

所以删除其中一个,它对我有用。

于 2015-01-27T14:33:07.383 回答
4

在某些情况下,当您根本不正确关闭您的指令时,您的指令会运行两次,如下所示:

<my-directive>Some content<my-directive>

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

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

于 2014-11-18T10:54:00.897 回答
2

一直在用 AngularJS 1.4 rc build 解决这个问题,然后意识到上述答案都不适用,因为它起源于撰写本文时Angular 1.4 和 Angular 2 的新路由器库。因此,我在这里为可能正在使用新的 Angular 路由库的任何人做一个说明。

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

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

于 2015-05-22T22:49:11.627 回答
2

就我而言,我发现两个视图使用同一个控制器。

$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'
    }
  }
});
于 2015-08-12T01:36:58.583 回答
2

我遇到的问题可能是切题的,但由于谷歌搜索让我想到了这个问题,这可能是合适的。使用 UI Router 时,问题对我来说很丑陋,但只有当我尝试使用浏览器刷新按钮刷新页面时。该应用程序使用带有父抽象状态的 UI 路由器,然后是父抽象状态的子状态。在应用程序run()功能上,有一个$state.go('...child-state...')命令。父状态使用 a resolve,起初我以为子控制器可能正在执行两次。

在 URL 附加哈希之前,一切都很好。
www.someoldwebaddress.org

然后一旦 url 被 UI Router 修改,
www.someoldwebaddress.org#/childstate

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

resolveon parent 状态是触发两次的状态。

也许这是一个杂牌;无论如何,这似乎确实消除了我的问题:在$stateProvider第一次调用的代码区域中,首先检查window.location.hash是否为空字符串。如果是,一切都很好;如果不是,则将window.location.hash设置为空字符串。然后似乎$state只有一次而不是两次尝试去某个地方。

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

于 2015-09-09T04:44:10.050 回答
2

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

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

或者

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

声明 $routeprovider 后,不要像在视图中那样提供控制器。而是使用视图中的标签。

于 2018-08-26T06:24:51.583 回答
1

就我而言,这是因为我使用的 url 模式

我的网址就像 /ui/project/:parameter1/:parameter2。

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

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

于 2015-05-13T13:28:35.960 回答
1

由于不同的原因,我发生了这种双重初始化。对于我的应用程序中的一些路由转换,我想强制滚动到页面顶部附近(例如,在分页搜索结果中......单击下一步应该将您带到第 2 页的顶部)。

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

$location.hash('top');

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

于 2015-08-24T16:09:02.637 回答
1

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

你可以在这里读更多关于它的内容

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

于 2016-09-22T12:41:25.947 回答
1

在我的情况下,将控制器重命名为不同的名称解决了这个问题。

控制器名称与“ angular-ui-tree ”模块存在冲突:我将控制器从“CatalogerTreeController”重命名为“ TreeController ”,然后该控制器开始在使用“ ui-tree ”指令的页面上启动两次,因为该指令使用名为“ TreeController ”的控制器。

于 2017-11-20T15:16:50.840 回答
0

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

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

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

于 2016-06-28T12:01:35.213 回答
0

我刚刚解决了我的问题,这实际上非常令人失望。它是一个离子混合应用程序,我使用了 ui-router v0.2.13。在我的例子中,有一个 epub 阅读器(使用 epub.js)在我导航到我的图书库并选择任何其他书时不断报告“未找到文档”。当我重新加载浏览器书时,它被完美呈现,但是当我选择另一本书时,又遇到了同样的问题。

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

于 2017-01-21T13:21:49.210 回答
0

我在 中遇到了同样的问题angular-route@1.6.7,这是因为正则表达式路由末尾的额外斜杠:

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

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

它工作正常。

于 2018-03-28T09:03:39.760 回答
0

只需在此处添加我的案例:

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

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

发生了什么?URL 中不允许参数值中的字符“@”。结果,angular-ui-router 两次创建了我的控制器:在第一次创建期间它传递了原始的“foo@bar”,在第二次创建期间它将传递编码版本“foo%40bar”。一旦我如上所示明确编码参数,问题就消失了。

于 2020-05-17T12:52:15.813 回答
0

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

<img alt="" class="logo" src="">
于 2020-08-04T02:43:25.937 回答
-1

我发现我的被调用了两次是因为我从我的 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() 被调用两次。希望它可以帮助某人。

于 2017-04-26T11:04:48.837 回答