两次对抗AngularJS执行控制器

时间:2013-03-20 21:43:16

标签: 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条记录插入我的数据库。我显然还在学习,因为我多年来一直在反对这个问题!

24 个答案:

答案 0 :(得分:1037)

app路由器指定导航到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">

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

答案 1 :(得分:125)

  

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

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

答案 2 :(得分:65)

我刚刚完成了这个,但问题与接受的答案不同。我真的把这个留给了我未来的自我,包括我修复它的步骤。

  1. Remove redundant controller declarations
  2. Check trailing slashes in routes
  3. Check for ng-ifs
  4. 检查是否有任何不必要的包裹ng-view来电(我不小心留在了ng-view,其中包含了我的实际ng-view。这导致三次调用我的控制器。)
  5. 如果您使用的是Rails,则应从turbolinks文件中删除application.js gem。我浪费了一整天才发现这一点。找到答案here
  6. 使用ng-app和bootstrap初始化应用程序两次。 Combating AngularJS executing controller twice
  7. 在指令的'link'-function中对整个元素使用$ compile时,该指令也有自己定义的控制器,并通过ng-click等在模板中使用该控制器的回调。找到答案here

答案 3 :(得分:12)

当控制器可以初始化两次时,只想添加一个案例(这对于angular.js 1.3.1来说是实际的):

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

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

要修复它,只需更改ng-if到ng-show / ng-hide,一切都会正常运行。

答案 4 :(得分:7)

想添加以供参考:

也可以通过在也在页面上运行的指令中引用控制器来引起双控制器代码执行。

e.g。

return {

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

当你的HTML中还有ng-controller =“myController”时

答案 5 :(得分:7)

angular-ui-router与Angular 1.3+一起使用时,存在Rendering views twice on route transition的问题。这导致执行控制器两次。所提议的解决方案都不适合我。

然而,将angular-ui-router从0.2.11更新为0.2.13解决了我的问题。

答案 6 :(得分:6)

我将我的应用及其所有依赖关系都解决了这个问题(详情请参阅:AngularJS app initiating twice (tried the usual solutions..)

最后,这是所有Batarang Chrome插件的错误。

this answer中的决议:

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

答案 7 :(得分:5)

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

<html ng-app="mTest1">

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

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

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

答案 8 :(得分:4)

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

答案 9 :(得分:4)

在某些情况下,如果您没有正确关闭指令,则指令会运行两次:

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

这将运行你的指令两次。 当你的指令运行两次时还会出现另一种情况:

确保您未在​​index.html TWICE 中加入指令!

答案 10 :(得分: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'
    }
  }
});

答案 11 :(得分:2)

我遇到的问题可能是切线,但由于谷歌搜索带我到这个问题,这可能是适当的。在使用UI路由器时,问题对我来说很难看,但只有当我尝试使用浏览器刷新按钮刷新页面时才会出现问题。该应用程序使用具有父抽象状态的UI路由器,然后子项关闭父项。在app run()函数上,有一个$state.go('...child-state...')命令。父状态使用resolve,起初我认为子控制器可能正在执行两次。

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

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

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

父状态的resolve是两次射击。

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

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

答案 12 :(得分:2)

在使用AngularJS 1.4 rc版本时,我一直在解决这个问题,然后意识到上述答案都不适用,因为它是在撰写本文时源于new router library for Angular 1.4 and Angular 2。因此,我正在为可能正在使用新Angular路径库的任何人发送一条注释。

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

Haven尚未找到可行的解决方法,但我相信这种行为与shaunxu提出的观点一致,并且希望这个问题能够在未来的新路径库的构建中得到解决,并且AngularJS 1.4发布。

答案 13 :(得分:1)

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

我是通过向$rootScope $on $viewContentLoaded添加一个监听器来执行此操作的(基于某些条件)执行的

$location.hash('top');

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

答案 14 :(得分:1)

在我的情况下,这是因为我使用的网址模式

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

在所有状态变化的情况下,我都不需要参数2。如果我不需要第二个参数,我的url就像/ ui / project /:parameter1 /。因此,每当我进行状态更改时,我的控制器都会刷新两次。

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

答案 15 :(得分:1)

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

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

controller getting called twice due to append params in url

答案 16 :(得分:1)

在我的情况下,将控制器重命名为其他名称解决了问题。

控制器名称的冲突与&#34; angular-ui-tree &#34; module:我从&#34; CatalogerTreeController&#34;重命名了我的控制器。到&#34; TreeController &#34;然后这个控制器开始在&#34; ui-tree &#34;的页面上启动两次。使用的指令,因为该指令使用名为&#34; TreeController &#34;的控制器。

答案 17 :(得分:0)

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

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

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

答案 18 :(得分:0)

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

我的解决很简单。我刚刚从reload:true

中的$state.go("app.reader", { fileName: fn, reload: true });移除了LibraryController

答案 19 :(得分:0)

我在INSERT INTO 1_a(door,skilt,lys,b_t,b_s,dato) VALUES(:door,:skilt,:lys,:b_t,:b_s,:dato) 中遇到了同样的问题,因为正则表达式路线末尾的额外斜杠

angular-route@1.6.7

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

并且它可以正常工作。

答案 20 :(得分:0)

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

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

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

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

答案 21 :(得分:0)

只需在这里添加我的案子:

我正在将 angular-ui-router .wrapper { display: grid; grid-auto-flow: row dense; grid-template-columns: repeat(3, 1fr); grid-gap: 10px; grid-auto-rows: minmax(300px, auto); }

一起使用

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

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

答案 22 :(得分:0)

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

export const uploadFile = async (file) => {
  let uploadTask = storage.ref(`products/${Date.now()}.${file.name.split('.').pop()}`).put(file);
  const snapshot = await uploadTask;
  const url = await snapshot.ref.getDownloadURL();
  return url;
}

答案 23 :(得分:-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()被调用两次。希望它可以帮到某人。