Luigi Woodhouse
Luigi Woodhouse

Reputation: 391

Mat Stepper does not go to next step when condition is met

I have 3 components, a mat-horizontal-stepper, component A and component B. Both components are called into the stepper. I want to navigate from component A to component B under the requirement that condition C is met. Condition C is implemented in a method called pay() and called in a button. pay() is a method that makes a payment and if the payment is successful , it should navigate to step 2 otherwise if payment is unsuccessful, it should remain on step 1.

Issue : when condition C is met, that is, payment is successful. I am not able to navigate to step 2.

See my code below

Component A ts file

@ViewChild(MatStepper) stepper!: MatStepper;

pay() {
 if(payment === "success"){
     this.goToNextStep()
   }
  else{
   console.warn("error")
 }

  goToNextStep() {
    console.log('Going to the next step...');
       if (this.stepper) {
      this.stepper.next();
   }
  }

Component A html file

<button (click)="pay()">
go to step 2 when payment is successful
<button>

Component B html file

payment successful

Stepper html file

<mat-horizontal-stepper #stepper [linear]="true">
 <mat-step>
 <app-component-a></app-component-a>
 </mat-step>

 <mat-step>
 <app-component-b></app-component-b>
 </mat-step>

</mat-horizontal-stepper>

Upvotes: 0

Views: 1060

Answers (2)

Luigi Woodhouse
Luigi Woodhouse

Reputation: 391

Solution 1 provided by @Zerotwelve

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-component-a',
  template: `
    <button (click)="pay()">Go to step 2 when payment is successful</button>
  `
})
export class ComponentA {
  @Output() paymentSuccess: EventEmitter<void> = new EventEmitter<void>();

  pay() {
    if (payment === 'success') {
      this.paymentSuccess.emit();
    } else {
      console.warn('Payment error');
    }
  }
}

<mat-horizontal-stepper #stepper [linear]="true">
  <mat-step>
    <app-component-a (paymentSuccess)="goToNextStep()"></app-component-a>
  </mat-step>

  <mat-step>
    <app-component-b></app-component-b>
  </mat-step>
</mat-horizontal-stepper>

import { Component, ViewChild } from '@angular/core';
import { MatStepper } from '@angular/material/stepper';

@Component({
  selector: 'app-stepper',
  templateUrl: './stepper.component.html',
  styleUrls: ['./stepper.component.css']
})
export class StepperComponent {
  @ViewChild(MatStepper) stepper!: MatStepper;

  goToNextStep() {
    console.log('Going to the next step...');
    if (this.stepper) {
      this.stepper.next();
    }
  }
}

Solution 2 provided by @Zerotwelve

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-component-a',
  template: `
    <button (click)="pay()">Go to step 2 when payment is successful</button>
  `
})
export class ComponentA {
  @Input() stepper: MatStepper | undefined;

  pay() {
    if (payment === 'success' && this.stepper) {
      this.stepper.next();
    } else {
      console.warn('Payment error');
    }
  }
}

<mat-horizontal-stepper #stepper [linear]="true">
  <mat-step>
    <app-component-a [stepper]="stepper"></app-component-a>
  </mat-step>

  <mat-step>
    <app-component-b></app-component-b>
  </mat-step>
</mat-horizontal-stepper>

Upvotes: 1

Zerotwelve
Zerotwelve

Reputation: 2361

Component A doesn't have access to the stepper in it's parent component. this.stepper will always be undefined.

Component A should emit an event and then you can call this.stepper.next(); from it's parent or you can add an @Input to Component A and pass the stepper as an input.

Upvotes: 1

Related Questions