首页 文章

两次对抗AngularJS执行控制器

提问于
浏览
517

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

22 回答

  • 64

    想补充参考:

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

    例如

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

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

  • 6

    当使用angular-ui-router与Angular 1.3时,有一个关于Rendering views twice on route transition的问题 . 这导致执行控制器两次 . 所提出的解决方案都不适合我 .

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

  • 1

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

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

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

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

  • 0

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

  • 1

    在我的情况下,将控制器重命名为另一个名称解决了问题 .

    有一个 conflict of controller names 与“angular-ui-tree " module: I renamed my controller from " CatalogerTreeController " to " TreeController " and then this controller starts to be initiated twice on the page where " ui-tree " directive used because this directive uses controller named " TreeController” .

  • 124

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

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

  • 12

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

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

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

  • 7

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

    <html ng-app="mTest1">
    

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

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

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

  • 4

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

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

  • -1

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

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

    但是我在_358208中也有这个:

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

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

  • 5

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

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

    尚未找到可行的解决方法,但我相信这种行为与shaunxu提出的观点一致,并且希望这个问题将在未来构建新路由库以及AngularJS 1.4版本中得到解决 .

  • 2

    我在 angular-route@1.6.7 中遇到了同样的问题,因为正则表达式路径末尾的 extra slash

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

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

    它工作正常 .

  • 1

    只想在控制器初始化两次时添加一个案例(这对于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,一切都会正常 .

  • 2

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

  • 0

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

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

    controller getting called twice due to append params in url

  • 2

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

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

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

    ......然后当我 refresh the page with the browser refresh button 时, $stateChangeStart 会发射两次,每次都指向 childstate .

    父状态的 resolve 是触发两次的 .

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

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

  • 1026

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

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

    $location.hash('top');
    

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

  • 1

    我把我的应用程序及其所有依赖项都撕成了这个问题(详情请参阅:AngularJS app initiating twice (tried the usual solutions..)

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

    this answer中的决议:

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

  • 0

    就我而言,我发现两个视图使用相同的控制器 .

    $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'
        }
      }
    });
    
  • 0

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

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

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

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

  • 7

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

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

    要么

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

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

  • 4

    我刚刚完成了这个,但问题与接受的答案不同 . 我真的离开这里是为了我未来的自我,包括我修复它的步骤 .

相关问题