Shubham Takode
Shubham Takode

Reputation: 533

How to override ion-back-button action in ionic 4 with angular 7

I wanted to stop navigation from one page to another page when user clicks on ion-back-button. I have some validation/check to be perform based on which app will decide whether to allow back action or not.

Upvotes: 14

Views: 11103

Answers (5)

Lincoln
Lincoln

Reputation: 3191

There is another alternative that may result in more natural solution using Angular events:)

All we need to do create a Directive that uses @Host and IonBackButtonDelegate to override the built-in ionic ion-back-button directive itself, and fire a new backClicked: InterceptedEvent if there are any observers listening for it.

Technically we don't need to fire a custom event/type, we could just fire the event itself, then check for event.defaultPrevented before executing the click handler, but... the approach below supports async event listeners via the callback pattern.

import { AfterViewInit, Directive, EventEmitter, Host, HostListener, Output } from '@angular/core';
import { IonBackButtonDelegate } from '@ionic/angular';

import { InterceptedEvent } from '../../model';


export interface InterceptedEvent {
  native: Event;
  proceed: () => void;
}

/**
 * Overrides the default ion-back-button directive.
 * @see https://github.com/ionic-team/ionic-framework/blob/main/angular/src/directives/navigation/ion-back-button.ts
 */
@Directive({
  selector: 'ion-back-button',
})
export class IonBackButtonOverrideDirective implements AfterViewInit {

  @Output()
  backClicked = new EventEmitter<InterceptedEvent>();

  private delegate: (ev: Event) => void;

  constructor(
    @Host() private host: IonBackButtonDelegate
  ) { }

  ngAfterViewInit(): void {
    if (this.backClicked.observed) {
      // This is where we wrap/delegate the default behavior of the Ionic directive
      this.delegate = this.host.onClick;
      this.host.onClick = () => { };
    }
  }

  @HostListener('click', ['$event'])
  async onClick(event: Event) {
    let executed = false;
    this.backClicked.emit({
      native: event,
      proceed: () => {
        if (!executed) {
          executed = true;
          this.delegate.apply(this.host, [event]);
        }
      }
    });
  }
}

And of course you need to make sure you properly register this in your Module.

@NgModule({
  declarations: [IonBackButtonOverrideDirective],
  ...

Your consuming code will need to use the new (backClicked) event:

        <ion-back-button (backClicked)="onBackClicked($event)"></ion-back-button>

And you will need to call InterceptedEvent.proceed() if you want the back button to do its original work:


  handleBackClicked(event: InterceptedEvent) {
      if (ignore event) {
        ... do your work here
      } else {
        event.proceed();
      }
  }

Done! Everything is type-safe and there's no need to use other ionic lifecycle events.

There are a lot of other ways to structure the event, like using event.preventDefault() itself to avoid the need to call proceed(), but the callback approach supported the most use-cases, such as async methods, etc, that I needed.

I'm sure there's a cleaner way. Feedback appreciated!

Upvotes: 1

arif08
arif08

Reputation: 795

Use IonBackButtonDelegate to override the functionality. Here's a simple example -

import { IonBackButtonDelegate } from '@ionic/angular';

...

export class TestPage {

  @ViewChild(IonBackButtonDelegate, { static: false }) backButton: IonBackButtonDelegate;

  ...
  // Registering
  ionViewDidEnter() {
    console.log('ionViewDidEnter');
    this.setUIBackButtonAction();
  }

  setUIBackButtonAction() {
    this.backButton.onClick = () => {
      // handle custom action here
    };
  }
}

Upvotes: 28

Mike Muniom McBriar
Mike Muniom McBriar

Reputation: 71

I could not find a controller-only solution (ionViewCanLeave was not firing) - my current hack is as below. It conditionally prevents/overrides ion-back-button, while still animating the button on click.

HTML:

<ion-back-button defaultHref="/" routerDirection="back">
    <div (click)="back($event)"></div>
</ion-back-button>

SCSS:

ion-back-button {
    & > div {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: 1;
    }
}

TS:

public back($event) {
    if (shouldPreventBack)
        $event.stopPropagation();
}

Upvotes: 1

Ravikumar Rajendran
Ravikumar Rajendran

Reputation: 504

This can be accomplished by Ionic Life Cyle Hooks

ionViewDidLoad: Fired only when a view is stored in memory. This event is NOT fired on entering a view that is already cached. It’s a nice place for init related tasks. ionViewWillEnter: It’s fired when entering a page, before it becomes the active one. Use it for tasks you want to do every time you enter in the view (setting event listeners, updating a table, etc.).

ionViewDidEnter: Fired when entering a page, after it becomes the active page. Quite similar to the previous one.

ionViewWillLeave: Fired when you leave a page, before it stops being the active one. Use it for things you need to run every time you are leaving a page (deactivate event listeners, etc.).

ionViewDidLeave: Fired when you leave a page, after it stops being the active one. Similar to the previous one.

ionViewWillUnload: Fired when a view is going to be completely removed (after leaving a non-cached view).

As a bonus track, there are two other powerful methods related to those events: nav guards. Those methods are focused on view access control (with authentication purposes).

Nav Guards If you wanted to prevent a user from leaving a view:

export class MyClass{
 constructor(
   public navCtrl: NavController
  ){}

  pushPage(){
    this.navCtrl.push(DetailPage);
  }

  ionViewCanLeave(): boolean{
   // here we can either return true or false
   // depending on if we want to leave this view
   if(isValid(randomValue)){
      return true;
    } else {
      return false;
    }
  }
} 

ionViewCanEnter: Fired before entering into a view, allows you to control whether the view can be accessed or not (returning true or false).

ionViewCanLeave: Fired before leaving a view, allows you to control whether the view can be left or not.

It is important to highlight that Nav Guards are executed before any other lifecycle event method.

Upvotes: 4

AddWeb Solution Pvt Ltd
AddWeb Solution Pvt Ltd

Reputation: 21681

Try this:

HTML:

 <ion-buttons slot="left">
            <ion-back-button (click)="BackButtonAction()">Back</ion-back-button>
 </ion-buttons>

TS:

BackButtonAction(){
    //action to be performed on back button
}

Upvotes: -2

Related Questions