Open sinedied opened 7 years ago
Hi, I've implemented your commit, but when the modal pops up, the view is blank and hidden. Would you know what is wrong?
UPDATE - SOLUTION: Turns out <ion-nav-bar>
causes the whole screen to go blank. Using <ion-header-bar>
instead works as expected.
@osirisr It should work with <ion-nav-bar>
, allowing for proper navigation with the changes provided.
Here is the generic modal we use for navigation, along with a dedicated service to handle show/hide using navigation events and properly take care of history stuff:
modal:
<ion-modal-view id="modal-nav-screen" class="modal-nav-screen">
<ion-nav-bar class="bar-positive has-shadow">
<ion-nav-title ng-bind="modalViewTitle"></ion-nav-title>
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view name="modal-nav"></ion-nav-view>
</ion-modal-view>
modal-navigation-service.ts
/**
* Modal navigation service: manages view navigation inside modals.
*/
export class ModalNavigationService {
static MODAL_NAV_VIEW_TARGET = 'modal-nav@';
static MODAL_SHOWN_EVENT = 'modalNav.shown';
static MODAL_HIDDEN_EVENT = 'modalNav.hidden';
private views: any;
private rootHistory: any;
private backView = null;
private currentView = null;
private modal: ionic.modal.IonicModalController = null;
private options: ionic.modal.IonicModalOptions = {
animation: 'slide-in-up',
focusFirstInput: false,
backdropClickToClose: false,
// Disabled to allow back view navigation
hardwareBackButtonClose: false
};
constructor(private $rootScope: ng.IRootScopeService,
private $ionicModal: ionic.modal.IonicModalService,
private $state: angular.ui.IStateService,
private $ionicHistory: ionic.navigation.IonicHistoryService) {
}
/**
* Initializes modal navigation service.
* Hooks are set up to automatically show/hide the navigation modal with special states targeting the "modal-nav@"
* view.
*/
init(): void {
if (!this.modal) {
// Set up modal with a separate named ion-nav-view
let options: ionic.modal.IonicModalOptions = Util.copy(this.options);
options.scope = this.$rootScope;
this.modal = this.$ionicModal.fromTemplate(<string>require('modal-navigation.modal.html'), options);
// Listen to view change to show/hide modal when needed
this.$rootScope.$on('$stateChangeStart', (event: ng.IAngularEvent,
toState: angular.ui.IState,
toParams: any,
fromState: angular.ui.IState) => {
let fromModal = fromState['views'] && fromState['views'][ModalNavigationService.MODAL_NAV_VIEW_TARGET];
let toModal = toState['views'] && toState['views'][ModalNavigationService.MODAL_NAV_VIEW_TARGET];
if (fromModal && !toModal && this.modal.isShown()) {
// If we are navigating from a modal state to a normal state, cancel event and hide modal
event.preventDefault();
this.hide();
} else if (!fromModal && toModal && !this.modal.isShown()) {
// If we are navigating from a normal state to a modal state, show modal
this.show();
}
});
// If the modal was not hidden with hide() method, properly restore state
this.$rootScope.$on('modal.hidden', (event: ng.IAngularEvent, modal: ionic.modal.IonicModalController) => {
if (modal === this.modal) {
this.hide();
}
});
}
}
/**
* Sets the modal navigation options.
* Must be used before calling the `init()` method.
* @param {IonicModalOptions} options The options to set.
*/
setOptions(options: ionic.modal.IonicModalOptions): void {
angular.extend(this.options, options);
}
/**
* Hides the modal and restore state history properly.
*/
hide(): void {
let currentView = this.currentView;
if (currentView !== null) {
// Restore ionic history properly
(<any>this.$ionicHistory).backView(this.backView);
(<any>this.$ionicHistory).currentView(currentView);
// delete all views created within the modal
let viewHistory = this.$ionicHistory.viewHistory();
_.each(viewHistory.views, (data: any, key: string) => {
if (!this.views[key]) {
delete viewHistory.views[key];
}
});
// all modals are created on the root scope
// reset history for the the 'root' history id
viewHistory.histories.root = this.rootHistory;
this.backView = null;
this.currentView = null;
this.modal.hide();
// bugfix : delete stateParam from stateId for route with id inside url
let stateId = currentView.stateId ? currentView.stateId.split('_').shift() : '';
// Properly restore browser's history in case of back navigation action
this.$state.go(stateId, currentView.stateParams);
this.$rootScope.$broadcast(ModalNavigationService.MODAL_HIDDEN_EVENT);
}
}
/**
* Checks if the current state is shown within a modal.
* @return {boolean} True if the current state is shown within a modal.
*/
isModalState(): boolean {
let views = this.$state.current['views'];
return !!(views && views[ModalNavigationService.MODAL_NAV_VIEW_TARGET]);
}
/**
* Shows the modal.
* This method should not be called directly, it it called when trying to navigate to a state targeting the
* "modal-nav@" view.
*/
private show(): void {
if (!this.modal.isShown()) {
// Save current state to properly restore ionic history when the modal is hidden
this.backView = this.$ionicHistory.backView();
this.currentView = this.$ionicHistory.currentView();
this.views = Util.copy(this.$ionicHistory.viewHistory().views);
this.rootHistory = Util.copy(this.$ionicHistory.viewHistory().histories.root);
this.$ionicHistory.nextViewOptions({ disableAnimate: true });
this.modal.show();
this.$rootScope.$broadcast(ModalNavigationService.MODAL_SHOWN_EVENT);
}
}
}
Just call modalNavigationService.init();
in your run block and you're set.
Here's an example route using this:
.state('editModal', {
views: {
'modal-nav@': {
template: <string>require('edit.html'),
controller: 'editController as vm'
}
}
})
Short description of what this resolves:
This allows using
<ion-nav-bar>
directive properly inside modal, with animations and back button working as expected.Changes proposed in this pull request:
<ion-nav-bar>
is within a modal or not and separate those within and those not when updating.<ion-view>
lifecycle events to be triggered when inside a modal that has a<ion-nav-view
You can now use nested states inside modals, with routes like this one:
Then you can use in a modal this way:
Ionic Version: 1.x
Fixes: #1838, #1893, trello issue, related forum post