I want to be able to override the BACK button on the navigation bar, and the hardware button.
I want this override to be for one specific controller, but not for the
I took Richard's suggestion and put it into a service to make it more reusable.
The Controller
angular.module('MainApp').controller('MyController', ['backButtonOverride'], function (backButtonOverride) {
// override back button for this controller
backButtonOverride.setup($scope, function() {
console.log("custom back");
});
}
The Service
angular.module('MainApp.services', []).factory('backButtonOverride', function ($rootScope, $ionicPlatform) {
var results = {};
function _setup($scope, customBackFunction) {
// override soft back
// framework calls $rootScope.$ionicGoBack when soft back button is pressed
var oldSoftBack = $rootScope.$ionicGoBack;
$rootScope.$ionicGoBack = function() {
customBackFunction();
};
var deregisterSoftBack = function() {
$rootScope.$ionicGoBack = oldSoftBack;
};
// override hard back
// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
customBackFunction, 101
);
// cancel custom back behaviour
$scope.$on('$destroy', function() {
deregisterHardBack();
deregisterSoftBack();
});
}
results.setup = _setup;
return results;
});
are you talking about the soft navigation as in the back button on the ion-header-bar or ion-nav-bar? cause that is a easy fix. Just make your own custom header bar for that template. so on that state template just use something like this.
<div class="bar bar-header bar-positive">
<button ng-click="someCustomFunction()" class="button button-clear button-light icon-left ion-chevron-left">Go Back</button>
</div>
this is my solution :)
Put this part of code in your app.js run function :
//** Go Back interception function ------------------------------------------
var currentScope;
var defaultGoBack = $rootScope.$ionicGoBack;
$rootScope.$ionicGoBack = function() {
if ( angular.isFunction( currentScope.customGoBack ) ) {
//assign default go back function to as a "super" function ^^
currentScope.customGoBack.super = defaultGoBack;
//if there is a custom back function, execute-it
currentScope.customGoBack();
} else {
//else, execute default go back
defaultGoBack();
}
};
//Store targetScope to global each time the view is changing
$rootScope.$on( '$ionicView.beforeEnter', function( event ) {
currentScope = event.targetScope;
});
Now, you are able to create a custom goback function in controllers :
$scope.customGoBack = function() {
console.log( "customGoBack" );
$scope.customGoBack.super();
};
This function will be automatically called when user tap on nav-back-button.
If you want to call goBack by yourself, you can do it by this way :
$rootScope.$ionicGoBack();
If you want to bypass the custom function whereas it is declared, here you go :
$ionicHistory.goBack();
You can assign different behavior for the back button directly in each controllers :)
The above answer to override $rootScope.$ionicGoBack partially works.
The problem is with the way of deregisterSoftBack. I tried the above mentioned $scope.$on('$destroy', a_function) and also the new $scope.$on('$ionicView.beforeLeave', a_function), neither works.
The reason for it: the new controller will be entered before the deregisterSoftBack thus make the deregister fail. So I modified the solution a bit to make it work.
change the
var oldSoftBack = $rootScope.$ionicGoBack
to
$rootScope.oldSoftBack = $rootScope.$ionicGoBack
deregister in $rootScope.$on("$stateChangeStart", your_function), the code is:
if ($rootScope.oldSoftBack) {
$rootScope.$ionicGoBack = $rootScope.oldSoftBack;
$rootScope.oldSoftBack = null;
}
Took the feedback from @raven.zuo and made some amends to un-register the state change event.
(function () {
'use strict';
angular
.module('appName')
.service('customBackButtonService', customBackButtonService);
customBackButtonService.$inject = ['$rootScope', '$ionicPlatform'];
function customBackButtonService($rootScope, $ionicPlatform) {
var service = {
setup: setup
};
return service;
////////////////
function setup(customBackFunction) {
// override soft back
// framework calls $rootScope.$ionicGoBack when soft back button is pressed
$rootScope.oldSoftBack = $rootScope.$ionicGoBack;
$rootScope.$ionicGoBack = function () {
customBackFunction();
};
var deregisterSoftBack = function () {
$rootScope.$ionicGoBack = $rootScope.oldSoftBack;
};
// override hard back
// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
customBackFunction, 101
);
// cancel custom back behaviour
var backStateChangeWatcher = $rootScope.$on('$stateChangeStart', function () {
if($rootScope.oldSoftBack){
deregisterHardBack();
deregisterSoftBack();
// Un-register watcher
backStateChangeWatcher();
}
});
}
}
})();
//Called via:
customBackButtonService.setup(function () {
console.log('custom back');
});
It is possible to override both buttons in your controller, without any changes the the HTML code.
To summarise:
$rootScope.$ionicGoBack()
$ionicPlatform.registerBackButtonAction()
Detailed explanations below.
The solution for overriding the soft navigation bar BACK button comes from understanding what Ionic does when that button is pressed.
From the Ionic docs for ion-nav-back-button, we already know that:
the button is automatically set to
$ionicGoBack()
on click/tap.
Searching the source code in ionic.bundle.js reveals how this is declared:
$rootScope.$ionicGoBack = function(backCount) {
$ionicHistory.goBack(backCount);
};
Overriding this in your own controller is simple. Make sure you pass $rootScope
into the controller and just modify the above code. It is a good idea to grab a pointer to the original function so you can restore it if required, or call into it when finished with your custom processing.
// grab pointer to original function
var oldSoftBack = $rootScope.$ionicGoBack;
// override default behaviour
$rootScope.$ionicGoBack = function() {
// do something interesting here
// uncomment below line to call old function when finished
// oldSoftBack();
};
The solution for overriding the Android hardware BACK button, for only one controller, comes from the return value of the registerBackButtonAction()
function, which does the deregistration of the override.
Call that deregistration method in the $scope.$on('$destroy'...
handler.
var doCustomBack= function() {
// do something interesting here
};
// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack= $ionicPlatform.registerBackButtonAction(
doCustomBack, 101
);
$scope.$on('$destroy', function() {
deregisterHardBack();
});
More details here:
A full solution would require the following:
The following code illustrates how this can be done:
// run this function when either hard or soft back button is pressed
var doCustomBack = function() {
console.log("custom BACK");
};
// override soft back
// framework calls $rootScope.$ionicGoBack when soft back button is pressed
var oldSoftBack = $rootScope.$ionicGoBack;
$rootScope.$ionicGoBack = function() {
doCustomBack();
};
var deregisterSoftBack = function() {
$rootScope.$ionicGoBack = oldSoftBack;
};
// override hard back
// registerBackButtonAction() returns a function which can be used to deregister it
var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
doCustomBack, 101
);
// cancel custom back behaviour
$scope.$on('$destroy', function() {
deregisterHardBack();
deregisterSoftBack();
});
This issue has been discussed on the Ionic forums & issues pages: