Home > Software engineering >  Pass input value from one component to another in Angular
Pass input value from one component to another in Angular

Time:10-04

I have two components, payment-info and confirmation. I'm trying to pass the input from payment-info into confirmation using a service (not parent/child relation). Right now the confirmation.component.html page will display the 'NA' text from the service model, but that value isn't being updated for some reason. Any help would be greatly appreciated!

Here is my payment-info.component.ts file code:

import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormGroup, FormControl } from '@angular/forms';
import { PaymentInfoService } from '../services/payment-info.service';

@Component({
  selector: 'app-payment-info',
  templateUrl: './payment-info.component.html',
  styleUrls: ['./payment-info.component.css']
})
export class PaymentInfoComponent implements OnInit {

  constructor(
    private formBuilder: FormBuilder,
    private paymentInfoService: PaymentInfoService
  ) { }

  paymentInfo = this.paymentInfoService.getPaymentInfo();

  checkoutForm = this.formBuilder.nonNullable.group({
    cardNumber: ''
  })

  ngOnInit(): void {
  }

  onSubmit(): void {
    this.setData(this.checkoutForm.value.cardNumber!);
  }

  setData(cardNumber: string) {
    this.paymentInfoService.setPaymentInfo(cardNumber);
  }

}

Here is my payment-info.component.html code:

<mat-card>
  <mat-card-title>Payment Details</mat-card-title>
  <mat-card-content>
    <form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">

      <table>
        <tr>
            <td>
              <mat-form-field >
                <input matInput id="cardNumber" formControlName="cardNumber" placeholder="Card Number">
              </mat-form-field>
            </td>
          </tr>
      </table>

        <button mat-raised-button color="accent" routerLink="/confirmation" type="submit" >Confirm Purchase</button>
    </form>
  </mat-card-content>
</mat-card>

Here is the code for confirmation.component.ts:

import { Component, OnInit } from '@angular/core';
import { PaymentInfoService } from '../services/payment-info.service';
import { Payment } from '../shared/models/Payment';

@Component({
  selector: 'app-confirmation',
  templateUrl: './confirmation.component.html',
  styleUrls: ['./confirmation.component.css']
})
export class ConfirmationComponent {
  payment! : Payment;
  constructor(private paymentInfoService: PaymentInfoService) {
    this.updatePaymentInfo();
  }

  ngOnInit(): void {
  }

  updatePaymentInfo(){
    this.payment = this.paymentInfoService.getPaymentInfo();
  }
}

Here is my code for confirmation.component.html:

<mat-card>
  <mat-card-title>CONFIRMATION</mat-card-title>
<mat-card-content>
  <form>
    <table>
    <tr>
        <td>
          <mat-form-field >
            <p>{{payment.cardNumber}}</p>
        </mat-form-field>
        </td>
      </tr>
    </table>
    <button mat-raised-button color="accent" routerLink="/" type="submit" >Return to catalog</button>
  </form>
</mat-card-content>
</mat-card>

Here is my payment-info.service.ts code:

import { Injectable } from '@angular/core';
import { Payment } from '../shared/models/Payment';

@Injectable({
  providedIn: 'root'
})
export class PaymentInfoService {

  paymentInfo: Payment = new Payment();

  setPaymentInfo(cardHolder:String, cardNumber: String, cvv: String, expirationDate: String){
    this.paymentInfo.cardNumber = cardNumber;
  }
  getPaymentInfo() {
    return this.paymentInfo;
  }
}

Lastly, here is the model I'm using for storing the input (Payment.ts):

export class Payment{
    cardNumber?: String = 'NA';
}

CodePudding user response:

Problem(s) & Concern(s)

Problem: The button didn't trigger the onSubmit function.

<button mat-raised-button color="accent" routerLink="/confirmation" type="submit" >Confirm Purchase</button>

You may place a debugger that the onSubmit function is not triggered and instead, it redirects to the confirmation page.

Concern 1: Incorrect calling setPaymentInfo method

From the PaymentService's setPaymentInfo method:

setPaymentInfo(
  cardHolder: String,
  cardNumber: String,
  cvv: String,
  expirationDate: String
) {
  this.paymentInfo.cardNumber = cardNumber;
}

While in PaymentInfoComponent:

setData(cardNumber: string) {
  this.paymentInfoService.setPaymentInfo(cardNumber);
}

You are incorrectly calling the method by providing parameters' values that do not match the method definition. You will get the compilation error.

You have to call the setPaymentInfo method by matching the method definition correctly as below:

setData(cardNumber: string) {
  this.paymentInfoService.setPaymentInfo('', cardNumber, '', '');
}

Concern 2: MatFormField error

In the confirmation page, the below HTML will get an error as MatFormField requires containing the MatFormFieldControl

<mat-form-field >
   <p>{{payment.cardNumber}}</p>
</mat-form-field>

Hence, you need to perform either of these actions:

  1. Remove the <mat-form-field> element as not required.

  2. Provide MatFormFieldControl to <mat-form-field> element.

<mat-form-field >
   <input matInput [value]="payment.cardNumber" readonly />
</mat-form-field>

Solution

  1. Modify the Payment Info page's submit button to remove the routerLink attribute.
<button
  mat-raised-button
  color="accent"
  type="submit"
  
>
  Confirm Purchase
</button>
  1. Inject Router service.
constructor(
  private formBuilder: FormBuilder,
  private paymentInfoService: PaymentInfoService,
  private router: Router
) {}
  1. Navigate to the confirmation page through the onSubmit function.
onSubmit(): void {
  this.setData(this.checkoutForm.value.cardNumber!);

  this.router.navigate(['/confirmation']);
}

Demo @ StackBlitz

  • Related