I want to use MatDialog in Angular 17 as a generic yes/no confirmation dialog. The call for it looks like this:
selectedAnswer = await this.dlg.ShowConfirmDialog("Abandon Changes?", "Are you sure you want to abandon the changes you have made and load a new account?", DialogTypeEnum.alert);
if (selectedAnswer) {
--Do This
}
else{
--Do something else
}
I am not getting any errors at compile, but the browser console shows this
NullInjectorError: NullInjectorError: No provider for DialogService!
at NullInjector.get (core.mjs:5682:27)
at R3Injector.get (core.mjs:6125:33)
at R3Injector.get (core.mjs:6125:33)
at R3Injector.get (core.mjs:6125:33)
at R3Injector.get (core.mjs:6125:33)
at R3Injector.get (core.mjs:6125:33)
at ChainedInjector.get (core.mjs:15427:36)
at lookupTokenUsingModuleInjector (core.mjs:4193:39)
at getOrCreateInjectable (core.mjs:4241:12)
at Module.ɵɵdirectiveInject (core.mjs:12045:19)
I can't figure out what I am missing. Any recommendations greatly appreciated. :)
This is my code:
account.components.ts(simplified)
import { DeclarationListEmitMode } from '@angular/compiler';
import { ChildToParentService } from '../../services/child-to-parent-service';
import { DialogService } from '../../services/dialog.service';
...AND OTHER IMPORTS
@Component({
selector: 'app-accounts',
standalone: true,
imports: [
MaterialUiModule,
CommonModule,... . . . .
],
templateUrl: './accounts.component.html',
styleUrl: './accounts.component.scss'
})
export class AccountsComponent implements OnInit {
//DECLARATIONS . . . . .
constructor(private accountsService: AccountsService,
private childToParentService: ChildToParentService,
private dlg: DialogService
) {
async loadAccount(accountId: string) {
var selectedAnswer = true;
if (this.profile.isDirty()) {
selectedAnswer = await this.dlg.ShowConfirmDialog("Abandon Changes?", "Are you sure you want to abandon the changes you have made and load a new account?", DialogTypeEnum.alert);
}
if (selectedAnswer) {
this.processes_editProcess.ResetProcessEditForm();
this.page.isEditMode = false;
this.accountsService.GetAccount(accountId).subscribe((response: any) => {
this.page.data = response;
});
}
}
}
}
DialogService.ts
import { MatDialog } from '@angular/material/dialog';
import { Observable, lastValueFrom } from 'rxjs';
import { ConfirmComponent } from '../dialogs/confirm/confirm.component';
import { IConfirmDialog } from '../global/confirm-dialog-Interface';
import { DialogType, DialogTypeEnum, DialogTypes } from 'app/global/dialog-types';
import { Component } from '@angular/core';
@Component({
templateUrl: '../dialogs/confirm/confirm.component.empty.html',
})
export class DialogService {
constructor(private dialog: MatDialog) {
}
async ShowConfirmDialog(title: string, message: string, dialog_Type: DialogTypeEnum) {
var dt = new DialogTypes();
var selectedDialogType = new DialogType();
switch (dialog_Type) {
case DialogTypeEnum.alert:
selectedDialogType = dt.alert;
break;
case DialogTypeEnum.information:
selectedDialogType = dt.information;
break;
case DialogTypeEnum.success:
selectedDialogType = dt.success;
break;
}
var audio = new Audio(selectedDialogType.soundSrc);
audio.load()
audio.volume = 0.05;
audio.play();
const answer = await lastValueFrom(
this.confirmDialog({
title: title,
message: message,
confirmCaption: 'Yes',
cancelCaption: 'No',
icon: selectedDialogType.icon,
color: selectedDialogType.color,
soundSrc: selectedDialogType.soundSrc
}));
/* this.dialog.closeDialog(); */
return answer;
}
public confirmDialog(data: IConfirmDialog): Observable<boolean> {
return this.dialog
.open(ConfirmComponent, {
data,
width: '400px',
disableClose: true,
})
.afterClosed();
}
closeDialog() {
this.dialog.closeAll();
}
}
AS @Yong Shun said the Dialog Service should be decorated as @Injectable
You can learn more about @Injectable and Dependency Injection here
@Injectable({
providedIn: 'root',
})
export class DialogService {
constructor(private dialog: MatDialog) {
}
async ShowConfirmDialog(title: string, message: string, dialog_Type: DialogTypeEnum) {
var dt = new DialogTypes();
var selectedDialogType = new DialogType();
switch (dialog_Type) {
case DialogTypeEnum.alert:
selectedDialogType = dt.alert;
break;
case DialogTypeEnum.information:
selectedDialogType = dt.information;
break;
case DialogTypeEnum.success:
selectedDialogType = dt.success;
break;
}
var audio = new Audio(selectedDialogType.soundSrc);
audio.load()
audio.volume = 0.05;
audio.play();
const answer = await lastValueFrom(
this.confirmDialog({
title: title,
message: message,
confirmCaption: 'Yes',
cancelCaption: 'No',
icon: selectedDialogType.icon,
color: selectedDialogType.color,
soundSrc: selectedDialogType.soundSrc
}));
/* this.dialog.closeDialog(); */
return answer;
}
public confirmDialog(data: IConfirmDialog): Observable<boolean> {
return this.dialog
.open(ConfirmComponent, {
data,
width: '400px',
disableClose: true,
})
.afterClosed();
}
closeDialog() {
this.dialog.closeAll();
}
}