menu

Questions & Answers

How can I trigger a function from a modal component that does not include the function in Angular 14?

I have been developing an e-commerce app with Angular 14.

I am currently working on a form that *can only be submitted upon accepting the "Terms & conditions" displayed in a modal.

The FormComponent and ModalComponent are sibling components.

In form.component.ts I have:

import { Component } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { FormGroup, FormControl } from '@angular/forms';
import { ModalComponent } from '../modal/modal.component';

@Component({
  selector: 'my-app',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css'],
})
export class FormComponent {
  public form: FormGroup = new FormGroup({});

  constructor(private dialog: MatDialog) {}

  ngOnInit() {
    this.form = new FormGroup({
      first_name: new FormControl(''),
      last_name: new FormControl(''),
      phone: new FormControl(''),
      email: new FormControl(''),
    });
  }

  public openDialog() {
    const dialogConfig = new MatDialogConfig();

    // Dialog options
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '420px';

    this.dialog.open(ModalComponent, dialogConfig);
  }

  public sendFormData() {
    console.log(this.form);
  }
}

In the form componant's template:

<h1>Get in touch</h1>

<form [formGroup]="form">
  <div class="form-grid">
    <mat-form-field appearance="outline" floatLabel="never">
      <mat-label class="mat-label">Fast name:</mat-label>
      <input class="mat-input" matInput formControlName="first_name" />
    </mat-form-field>

    <mat-form-field appearance="outline" floatLabel="always">
      <mat-label class="mat-label">Last name:</mat-label>
      <input class="mat-input" matInput formControlName="last_name" />
    </mat-form-field>

    <mat-form-field appearance="outline" floatLabel="never">
      <mat-label class="mat-label">Phone:</mat-label>
      <input class="mat-input" matInput formControlName="phone" />
    </mat-form-field>

    <mat-form-field appearance="outline" floatLabel="never">
      <mat-label class="mat-label">Email:</mat-label>
      <input class="mat-input" matInput formControlName="email" />
    </mat-form-field>
  </div>
  <div class="center">
    <button (click)="openDialog()" mat-raised-button color="primary">
      Submit
    </button>
  </div>
</form>

In modal.component.ts I have:

import { Component, OnInit } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css'],
})
export class ModalComponent implements OnInit {
  constructor(private dialogRef: MatDialogRef<ModalComponent>) {}

  ngOnInit(): void {}

  accept() {
    console.log('Terms accepted!');
  }

  reject() {
    this.dialogRef.close();
  }
}

In modal.component.html I have:

<div mat-dialog-title>
  <h2>Terms & Conditions</h2>
</div>
<div mat-dialog-content>
  <p>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur expedita
    ipsam assumenda sed non aut possimus, dolores ullam voluptates voluptatum
    distinctio aspernatur neque velit eum, eveniet voluptas omnis. Veritatis,
    architecto?
  </p>
  
</div>
<mat-dialog-actions>
  <button mat-raised-button color="primary" (click)="reject()">Reject</button>
  <button mat-raised-button color="primary" (click)="accept()">Accept</button>
</mat-dialog-actions>

I have put it all together in THIS Stackblitz.

The goal

The goal is to trigger the function sendFormData() from the form component from inside the accept() function of the modal component?

For achieving this, I did:

accept() {
    console.log('Terms accepted!');
    this.FormComponent.sendFormData();
}

The above does not work.

What is the easiest and most reliable way to achieve the desired result?
Answers(1) :

In your dialog component, you pass a result to the close() function:

accept() {
  this.dialogRef.close('ACCEPTED');
}

reject() {
  this.dialogRef.close('REJECTED');
}

In your form component's openDialog() function, you handle the result:

public openDialog() {
  const dialogConfig = new MatDialogConfig();
  dialogConfig.disableClose = true;
  dialogConfig.autoFocus = true;
  dialogConfig.width = '420px';

  const dialogRef = this.dialog.open(ModalComponent, dialogConfig);
  dialogRef.afterClosed().subscribe((result) => {
    if (result === 'ACCEPTED') {
      this.sendFormData();
    }
  });
}