Angularjs $scope.$on(';$stateChangeStart';)和$modal对话框
我有一个AngularJs应用程序,它正在检测状态的变化(使用ui.router),向用户提供保存未保存的变化的选项。现在,我通过确认对话框执行此操作:Angularjs $scope.$on(';$stateChangeStart';)和$modal对话框,angularjs,twitter-bootstrap,dialog,typescript,angular-ui-router,Angularjs,Twitter Bootstrap,Dialog,Typescript,Angular Ui Router,我有一个AngularJs应用程序,它正在检测状态的变化(使用ui.router),向用户提供保存未保存的变化的选项。现在,我通过确认对话框执行此操作: $scope.$on('$stateChangeStart', () => { if (self.changed && confirm('There are unsaved changes. Do you want to save them?')) this.save(); }); 我想将其更改为
$scope.$on('$stateChangeStart', () => {
if (self.changed && confirm('There are unsaved changes. Do you want to save them?'))
this.save();
});
我想将其更改为使用bootstrap ui库中的$modal
对话框。我遇到的问题是,$modal.open()
调用会立即返回(异步),因此在打开对话框之前状态会发生变化,而对话框从未打开过
$scope.$on('$stateChangeStart', () => {
if (self.changed)
this.$dialog.open({...}).result.then(()=>{
this.save();
});
});
有没有办法克服这个问题,或者我一直坚持使用普通的javascript确认对话框?您应该收听
$locationChangeStart
事件,如果您有未保存的更改,则执行event.prventDefault()
并继续使用ui引导模式的确认对话框的逻辑。问题是,在较新的angular版本中,事件的顺序略有改变,$stateChangeStart
发生得有点晚,无法在那里执行逻辑。如果你陷入困境,我可以为你提供一个有效的例子。现在,以下是示例代码:
$scope.$on(“$locationChangeStart”,()=>{
如果(自我改变){
event.preventDefault();
这个.dialog.open({…}).result.then(()=>{
这是save();
//如果需要,请在保存后选择重定向逻辑
});
}
});代码>如果要处理状态更改事件,最好在应用程序上应用该事件并使用$modal服务。你可以在这里找到详细的解释
但是,这给出了一个在状态发生变化时适用于每个状态变化的示例,但您可以使其适用于单个或指定的状态,如下所示:
app.run(function ($rootScope) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if(toState.name =="desiredState") {
event.preventDefault();
// perform your task here
}
});
});
这就是我解决问题的方法。在我的应用程序中,我使用AppCtrl(父级)来处理导航、脏状态等
function AppCtrl($rootScope, events, modalDialog) {
var vm = this,
handlingUnsavedChanges = false;
function isDirty() {
return $rootScope.$broadcast(events.CAN_DEACTIVATE).defaultPrevented;
}
function onStateChangeStart(event, toState, toParams) {
if (handlingUnsavedChanges) {
// if the dirty state has already been checked then continue with the state change
return;
}
// check for dirty state
if (isDirty()) {
// cancel navigation
event.preventDefault();
modalDialog
.confirmNavigation()
.then(function () {
// ignore changes
handlingUnsavedChanges = true;
$state.go(toState.name, toParams);
});
}
// Else let the state change
}
$rootScope.$on('$stateChangeStart', onStateChangeStart);
}
<div ng-controller="AppCtrl as app">
<div ui-view />
</div>
使用应用程序的ui路由器
和run
部分中的设置,您可以做得非常好。
关键部分基本上是观察(“$stateChangeStart”)上的$rootScope.$on
事件。
我用plunker展示了整个解决方案:主要部分在scipt.js
中,如下所示:
routerApp.run(function($rootScope, $uibModal, $state) {
$rootScope.modal = false; // this has to be set so the modal is not loaded constantly, and skips the 1st application entrance
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
if ($rootScope.modal) {
event.preventDefault(); //this stops the transition
$rootScope.modal = false;
var modalInstance = $uibModal.open({
templateUrl: 'modal.html'
});
modalInstance.result.then(function(selectedItem) {
console.log('changing state to:'+ toState.name);
$state.go(toState, {}, {reload:true});
}, function() {
console.log('going back to state:'+ fromState.name);
$state.go(fromState, {}, {reload:true});
});
} else {
$rootScope.modal = true;
}
});
});
因为我不太习惯使用广播
,所以我使用了下面的方法
在显示我的JQuery
对话框之前,我只需取消当前事件(状态更改)。若用户选择“是”,则我触发$state.go
,若选择“取消/否”-我们不需要做任何事情,我们已经取消了事件
$rootScope.$on('$stateChangeStart',function (event, toState, toParams, fromState, fromParams, options) {
console.log('$stateChangeStart- fromState= '+fromState.name +'-toState= '+toState.name);
/*If user starts to change state, show him a confirmation dialog
* If user selects 'Yes' - continue with state change and go in pause mode for collection.
* If user selects 'No'- stop state change.
*/
if (/*some condition*/) {
/*stateChangeStart gets triggered again by $state.go initiated from our modal dialog-
hence avoid extra cycle of listening to stateChangeStart*/
if (service.stateChangeTriggeredByDialog) {
service.stateChangeTriggeredByDialog = false;
return;
}
if (fromParams.paramName !== toParams.paramName) {
event.preventDefault();
Dialog.confirm({
dialogClass: 'my-customDialog',
template: $translate.instant('STATE_CHANGE_MSG'),
resizable: false,
width: 550
}).then(function () {
console.log('User choose to continue state change');
service.stateChangeTriggeredByDialog = true;
$state.go(toState, toParams, { inherit: false });
}, function () {
console.log('User choose to stop state change');
});
}
}});
是什么触发了状态变化?可能需要在那里捕获它,甚至不需要输入更改它可能是ui sref链接或通过$state.go
手动更改状态。我想检测用户何时退出该状态,无论原因是什么。我唯一能想到的是基于$rootScope或服务中存储的标志阻止事件,并使用模式事件切换标志。如果一切顺利的话,$state.go()
将非常重要simpler@CarlesCompany,@AmanMahajan,我在下面添加我的答案版本,因为我现在不太习惯使用广播。请建议我的方法是否正确。@AmanMahajan,我在我的服务中添加了stateChangeStart
listener。可以在任何地方添加,对吗?
$rootScope.$on('$stateChangeStart',function (event, toState, toParams, fromState, fromParams, options) {
console.log('$stateChangeStart- fromState= '+fromState.name +'-toState= '+toState.name);
/*If user starts to change state, show him a confirmation dialog
* If user selects 'Yes' - continue with state change and go in pause mode for collection.
* If user selects 'No'- stop state change.
*/
if (/*some condition*/) {
/*stateChangeStart gets triggered again by $state.go initiated from our modal dialog-
hence avoid extra cycle of listening to stateChangeStart*/
if (service.stateChangeTriggeredByDialog) {
service.stateChangeTriggeredByDialog = false;
return;
}
if (fromParams.paramName !== toParams.paramName) {
event.preventDefault();
Dialog.confirm({
dialogClass: 'my-customDialog',
template: $translate.instant('STATE_CHANGE_MSG'),
resizable: false,
width: 550
}).then(function () {
console.log('User choose to continue state change');
service.stateChangeTriggeredByDialog = true;
$state.go(toState, toParams, { inherit: false });
}, function () {
console.log('User choose to stop state change');
});
}
}});