如何从 PopupController 调用 openAddCardModal()
结论
不要在 PopupController 中直接调用 ModalController 的方法。两个 Controller 通常使用不同的 $scope,也不应互相持有对方的实例。
按现有结构,可以由 PopupController 广播事件,ModalController 收到事件后再调用 openAddCardModal()。还要处理 $ionicModal.fromTemplateUrl() 的异步初始化,避免用户点击时 modal 尚未创建。
实现方式
在 PopupController 中注入 $rootScope,点击 “Add” 时广播事件:
function PopupController(
$scope,
$rootScope,
$ionicPopup,
$timeout,
$state
) {
$scope.showPaymentOptionsPopup = function() {
$ionicPopup.confirm({
title: 'Payment Options',
cssClass: 'popup-vertical-buttons',
buttons: [
{
text: 'Add',
type: 'button-positive',
onTap: function() {
$rootScope.$broadcast('payment:add-card');
}
},
{
text: 'Edit',
type: 'button-positive',
onTap: function() {
}
},
{
text: 'Close',
type: 'button-dark',
onTap: function() {
}
}
]
});
};
}
在 ModalController 中监听这个事件:
function ModalController($scope, $ionicModal, $stateParams) {
var modalReady = $ionicModal.fromTemplateUrl(
'views/payment-add-card.view.html',
{
scope: $scope,
animation: 'slide-in-up'
}
).then(function(modal) {
$scope.addCardModal = modal;
return modal;
});
$scope.openAddCardModal = function() {
return modalReady.then(function(modal) {
return modal.show();
});
};
$scope.closeAddCardModal = function() {
if ($scope.addCardModal) {
return $scope.addCardModal.hide();
}
};
var stopListening = $scope.$on('payment:add-card', function() {
$scope.openAddCardModal();
});
$scope.$on('$destroy', function() {
stopListening();
if ($scope.addCardModal) {
$scope.addCardModal.remove();
}
});
}
为什么不能直接调用
$scope.openAddCardModal 只存在于 ModalController 对应的作用域中。除非两个 Controller 正好处于可以通过父子 $scope 访问的层级,否则 PopupController 无法直接取得这个函数。
即使能通过下面的方式访问,也不建议这样写:
$scope.$parent.openAddCardModal();
这种写法依赖页面的 DOM 和作用域层级。模板结构或路由一旦改变,调用就可能失效。
注意事项
$ionicModal.fromTemplateUrl() 返回 Promise,modal 不会同步创建。把 modal.show() 放进 modalReady.then(),可以避免下面这类错误:
Cannot read property 'show' of undefined
如果弹窗和 modal 属于同一个页面功能,可以让同一个 Controller 同时管理 $ionicPopup 和 $ionicModal,代码会更简单。如果多个页面都要打开这个 modal,则可以把 modal 的创建、打开和销毁逻辑封装到 AngularJS service 中。相比全局事件,这种方式更容易维护。
备注:内容仅供参考。
