避免在 Angular UI 模式中使用 $timeout
Avoid using $timeout in Angular UI Modal
In this plunk 我有一个包裹在指令中的 Angular UI 模态框。从控制器中,我调用了一个方法来打开模式,但为此我需要使用 $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;
});
使用超时来任意等待代码执行通常是不好的。正如您在问题中所述,根据您正在加载的页面的整体上下文,您无法保证该指令将在您的控制器运行时准备就绪。
你这里的抽象层次似乎太多了。某些东西正在渲染一个 div,当它完全渲染时,会显示一个模态。
只让渲染 div 的东西创建并显示模式不是更有意义吗?
为了避免使用$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();
}
关于评论@Eduardo La Hoz Miranda
you should be ok with the timeout. I would decrease the time to 0, tho, since timeout will send your call to the bottom of the event loop.
通常当我们用 0 毫秒或不带参数初始化 $timeout
时:
$timeout(function(){
$scope.modalCtl.openModal();
});
我们在下一个摘要周期a.e之前将$scope.modalCtl.openModal()
延迟到运行。排在最后。所以在这种情况下,指令 link 将 运行 从头到尾第一个,只有在您进入 $timeout
之后。
The $timeout may work in a development environment but may fail in production.
在生产环境中,您有相同的代码。它应该工作。我相信问题出在其他地方。如果您对 $timeout
没有信心,请使用我发布的上述方式。
当指令的 link 功能完成时,它可以发出一条消息,表明它已准备就绪。
并且控制器侦听此消息并在收到时显示模态。
代码:
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;
});
In this plunk 我有一个包裹在指令中的 Angular UI 模态框。从控制器中,我调用了一个方法来打开模式,但为此我需要使用 $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;
});
使用超时来任意等待代码执行通常是不好的。正如您在问题中所述,根据您正在加载的页面的整体上下文,您无法保证该指令将在您的控制器运行时准备就绪。
你这里的抽象层次似乎太多了。某些东西正在渲染一个 div,当它完全渲染时,会显示一个模态。
只让渲染 div 的东西创建并显示模式不是更有意义吗?
为了避免使用$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();
}
关于评论@Eduardo La Hoz Miranda
you should be ok with the timeout. I would decrease the time to 0, tho, since timeout will send your call to the bottom of the event loop.
通常当我们用 0 毫秒或不带参数初始化 $timeout
时:
$timeout(function(){
$scope.modalCtl.openModal();
});
我们在下一个摘要周期a.e之前将$scope.modalCtl.openModal()
延迟到运行。排在最后。所以在这种情况下,指令 link 将 运行 从头到尾第一个,只有在您进入 $timeout
之后。
The $timeout may work in a development environment but may fail in production.
在生产环境中,您有相同的代码。它应该工作。我相信问题出在其他地方。如果您对 $timeout
没有信心,请使用我发布的上述方式。
当指令的 link 功能完成时,它可以发出一条消息,表明它已准备就绪。
并且控制器侦听此消息并在收到时显示模态。
代码:
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;
});