避免在Angular UI Modal中使用$ timeout

时间:2017-10-18 01:48:54

标签: angularjs angularjs-directive angular-ui-bootstrap angular-ui

In this plunk我有一个Angular UI Modal包含在一个指令中。从控制器,我调用一个方法来打开模态,但为此我需要使用$timeout,否则,DOM还没有完成渲染指令。

这似乎有效,但是,如果在$timeout到期后需要完成的任何事情尚未完成,会发生什么? $timeout可能在开发环境中有效,但可能在生产中失败。使用$timeout是不好的做法?如何在这个例子中避免使用它?

HTML

<div modal control="modalCtl"></div>

的Javascript

var app = angular.module('app', ['ui.bootstrap']);

app.controller('myCtl', function($scope,$timeout) {
    $scope.modalCtl = {};       
    $timeout(function(){
        $scope.modalCtl.openModal();
    },100);         
})
.directive('modal', function ($uibModal) {
    var directive = {};
    directive.restrict = 'EA';
    directive.scope = {    
        control: '='
    };
    directive.link = function (scope, element, attrs) {
        scope.control = scope.control || {};            
        scope.control.openModal = function() {
            scope.modalInstance = $uibModal.open({
                template: '<button ng-click="close()">Close</button>',
                scope: scope
            })
        };
        scope.close = function () {
            scope.modalInstance.close();
        };
    };
    return directive;
});

3 个答案:

答案 0 :(得分:7)

为了避免使用$timeout,指令可以在一切准备就绪时通知控制器。看看:

.directive('modal', function ($uibModal) {      
    var directive = {};    
    directive.restrict = 'EA';    
    directive.scope = {    
            control: '=',
            onReady: '&'  // <-- bind `onReady` with  `onModalReady`            
        };

    directive.link = function (scope, element, attrs) {

      scope.control = scope.control || {};

      scope.control.openModal = function() {
          scope.modalInstance = $uibModal.open({
              template: '<button ng-click="close()">Close</button>',
              scope: scope
            })                
        };

        scope.close = function () {
            scope.modalInstance.close();
        };

      scope.onReady(); // <-- notify controller
    };    
    return directive;    
});

输出HTML:

 <div modal on-ready="onModalReady()" control="modalCtl"></div>

我们的控制人员:

 $scope.onModalReady = function(){
   $scope.modalCtl.openModal();
 }

Changed Plunker

关于评论@Eduardo La Hoz Miranda

  

你应该对超时感到满意。我会把时间减少到0,因为超时会将你的呼叫发送到事件循环的底部。

通常我们用0毫秒初始化$timeout或没有参数:

 $timeout(function(){
   $scope.modalCtl.openModal();
 }); 

我们推迟$scope.modalCtl.openModal()下一个摘要周期a.e之前运行。最后排队。因此,在这种情况下,指令链接将从开始到结束运行1,并且仅在您输入$timeout之后。

  

$ timeout可能在开发环境中有效,但可能在生产中失败。

在生产中,您拥有相同的代码。它应该工作。我相信问题出在其他方面。如果你对$timeout使用上面提到的方式没有信心,我发布了。

Your Logged Plunker

答案 1 :(得分:1)

当指令的链接功能完成时,它会发出一条消息,表明它已准备就绪。

控制器监听此消息并在收到时显示模态。

代码:

var app = angular.module('app', ['ui.bootstrap']);

app.controller('myCtl', function($scope,$timeout) {
  $scope.modalCtl = {};
    $scope.$on("hey", function() {
    $scope.modalCtl.openModal();
  });
})
.directive('modal', function ($uibModal) {

  var directive = {};

  directive.restrict = 'EA';

  directive.scope = {    
    control: '='
  };

  directive.link = function (scope, element, attrs) {

  scope.control = scope.control || {};

  scope.control.openModal = function() {
    scope.modalInstance = $uibModal.open({
      template: '<button ng-click="close()">Close</button>',
      scope: scope
  })

  };

  scope.close = function () {
        scope.modalInstance.close();
  };

  scope.$emit("hey");
};

return directive;
});

答案 2 :(得分:0)

对代码执行的任意等待使用超时通常是不好的。正如您在问题中所述,根据您正在加载的页面的整体上下文,您无法保证在控制器运行时该指令就绪。

这里似乎有太多的抽象层次。有些东西渲染div,当它完全渲染时,会显示一个模态。

仅仅让渲染div的东西创建并显示模态会更有意义吗?