Reputation: 561
I am trying to use the Angular material module to open a model on click of a button. I have followed the example as suggested in the https://material.angular.io/components/dialog/examples.
However, I see that as try to run the application, I see the following error -
errors.js:48 ERROR Error: Uncaught (in promise): Error: StaticInjectorError[MatDialog]:
StaticInjectorError[MatDialog]:
NullInjectorError: No provider for MatDialog!
Error: StaticInjectorError[MatDialog]:
StaticInjectorError[MatDialog]:
NullInjectorError: No provider for MatDialog!
at _NullInjector.get (injector.js:31)
at resolveToken (injector.js:387)
at tryResolveToken (injector.js:330)
at StaticInjector.get (injector.js:170)
at resolveToken (injector.js:387)
at tryResolveToken (injector.js:330)
at StaticInjector.get (injector.js:170)
at resolveNgModuleDep (ng_module.js:103)
at NgModuleRef_.get (refs.js:1037)
at resolveDep (provider.js:455)
at _NullInjector.get (injector.js:31)
at resolveToken (injector.js:387)
at tryResolveToken (injector.js:330)
at StaticInjector.get (injector.js:170)
at resolveToken (injector.js:387)
at tryResolveToken (injector.js:330)
at StaticInjector.get (injector.js:170)
at resolveNgModuleDep (ng_module.js:103)
at NgModuleRef_.get (refs.js:1037)
at resolveDep (provider.js:455)
at resolvePromise (zone.js:824)
at resolvePromise (zone.js:795)
at eval (zone.js:873)
at ZoneDelegate.invokeTask (zone.js:425)
at Object.onInvokeTask (ng_zone.js:575)
at ZoneDelegate.invokeTask (zone.js:424)
at Zone.runTask (zone.js:192)
at drainMicroTaskQueue (zone.js:602)
at ZoneTask.invokeTask [as invoke] (zone.js:503)
at invokeTask (zone.js:1540)
defaultErrorLogger @ errors.js:48
I have the following setup of the project files
app.module.ts
I have imported the MatDialogModule and also placed the same in the imports. Within the Entry components, I have added the component that needs to be rendered in the modal.
import { MatDialogModule } from '@angular/material/dialog';
@NgModule({
imports: [ BrowserModule, BrowserAnimationsModule, FormsModule, NgbModule.forRoot(), ReactiveFormsModule,
HttpClientModule, routing, MatTabsModule, MatDialogModule ],
declarations: [ AppComponent, AppHeaderComponent, SignInComponent, RecruitmentHomeComponent, JobTemplatesComponent, CreateJobTemplateComponent ],
bootstrap: [ AppComponent ],
entryComponents: [CreateJobTemplateComponent],
providers: [AuthGuard, UserService, AuthenticationService]
})
Code in job-templates.component.ts
This is the file which is responsible for invoking the model on click of a button added to its template.
import { Component, OnInit } from '@angular/core';
import { CreateJobTemplateComponent } from './create-job-template/create-job-template.component';
import { MatDialog } from '@angular/material';
@Component({
selector: 'app-job-templates',
templateUrl: './job-templates.component.html',
styleUrls: ['./job-templates.component.css']
})
export class JobTemplatesComponent implements OnInit {
constructor(public dialog: MatDialog) { }
ngOnInit() {
}
createjobtemplate(){
let dialogRef = this.dialog.open(CreateJobTemplateComponent, {
width: '250px'
});
//Set the dialogRef property of opened dialog with the obtained ref
dialogRef.componentInstance.dialogRef = dialogRef;
}
}
create-job-template.component.ts
This component will render itself in the modal dialog.
import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef } from '@angular/material';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
selector: 'app-create-job-template',
templateUrl: './create-job-template.component.html',
styleUrls: ['./create-job-template.component.css']
})
export class CreateJobTemplateComponent implements OnInit {
form: FormGroup;
constructor(private formBuilder: FormBuilder, public dialogRef: MatDialogRef<CreateJobTemplateComponent>) { }
ngOnInit() {
this.form = this.formBuilder.group({
filename: ''
})
}
submit(form) {
this.dialogRef.close(`${form.value.filename}`);
}
}
Can anyone let me know where I am going wrong here? Most of the errors that I have looked for talk about failure to Inject MatDialogRef, but I find this error for MatDialog.
Also I was looking through this blog as well to make sure I followed the same steps. https://blog.thoughtram.io/angular/2017/11/13/easy-dialogs-with-angular-material.html
For Reference, I have the code at
https://stackblitz.com/edit/angular-fhhmff
Upvotes: 12
Views: 29599
Reputation: 2102
My suggestion is to simplify the way your dialog gets instantiated using the pattern below. With this pattern, the "parent" component is the only thing that needs to be aware of managing the dialog. The template file looks something like this:
<ng-template #dialog_template>
<app-the-dialog
[input_data]="data"
(ok)="onSelect($event)"
(cancel)="onCancel()">
</app-the-dialog>
</ng-template>
<div>
<button (click)="openDialog()">Open Dialog</button>
<!-- Everything else in the template goes here -->
</div>
The parent component manages the dialog something like this:
import { Component, ViewChild, TemplateRef } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { TheDialogComponent } from './the-dialog.component';
@Component({ ... })
export class YourComponent {
@ViewChild('dialog_template', {static: true }) private dialog_template: TemplateRef<any>;
private dialogRef: MatDialogRef<TheDialogComponent>;
constructor(
public dialog: MatDialog,
) { }
public openDialog(): void {
this.dialogRef = this.dialog.open(this.dialog_template, {
width: '85%',
height: '85%'
});
}
public onSelect(data_emitted_from_dialog: any): void {
// ...Respond to OK event...
this.dialogRef.close();
}
public onCancel(): void {
// ...Respond to Cancel event...
this.dialogRef.close();
}
}
You can develop TheDialogComponent
independently of its caller, and the component structure looks exactly like a typical component, with no special syntax/awareness that it's a dialog.
I battled this very same NullInjectorError: No provider for MatDialogRef!
error for hours, until I uncovered the pattern above. The official MatDialog
docs make me angry for how complex they make it seem: The suggested syntax is really dense, and the wiring spans three disparate places: The parent component that triggers the dialog, the component that is the dialog, and the containing module's entryComponents
property. It shouldn't be that hard to open a simple dialog box. This solution above is more elegant because:
constructor(@Inject(MAT_DIALOG_DATA) public data: any)
? What?) just to get data in.entryComponents
)[input]
and (output)
syntax binds directly to the parent model, which I bet is what you wanted in the first place.Enjoy!
Upvotes: 3
Reputation: 530
This is for Angular 9 / Angular Material 9
As teddybear mentioned:
import { MatDialog } from '@angular/material';
should be
import { MatDialog } from '@angular/material/dialog';
I had to restart my Angular Live Development Server to resolve the error.
Another common issue I see is missing MatDialogModule
in AppModule
imports (which you have) as the error is the same as this one
Also you no longer need entryComponents
in AppModule
Upvotes: 1
Reputation: 570
Had the same error. Turns out I was importing
import { MatDialog } from '@angular/material';
Should have been
import { MatDialog } from '@angular/material/dialog';
Upvotes: 5
Reputation: 111
it seems that you forgot to add the injector of the MAT_DIALOG_DATA in the constructor:
@Inject(MAT_DIALOG_DATA) public data: any
In the CreateJobTemplateComponent you need to import the MAT_DIALOG_DATA:
import { MAT_DIALOG_DATA } from '@angular/material';
and the constructor should be:
constructor(@Inject(MAT_DIALOG_DATA) public data: any,
private formBuilder: FormBuilder,
public dialogRef: MatDialogRef<CreateJobTemplateComponent>) { }
Upvotes: 2