angular material No provider for MatDialog! Error

試著忘記壹切 提交于 2020-06-25 00:30:12

问题


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


回答1:


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>) { }



回答2:


Had the same error. Turns out I was importing

import { MatDialog } from '@angular/material';

Should have been

import { MatDialog } from '@angular/material/dialog';




回答3:


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




回答4:


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:

  • The dialog component is just a component that declares @Inputs and @Outputs. No crazy injection syntax (constructor(@Inject(MAT_DIALOG_DATA) public data: any)? What?) just to get data in.
  • The dialog is declared within the "parent" component's template, right where you would expect to find it. (And referencing the dialog component in a template eliminates the need to declare it on the module entryComponents)
  • With the dialog component instantiated in the parent template, standard Angular [input] and (output) syntax binds directly to the parent model, which I bet is what you wanted in the first place.

Enjoy!



来源:https://stackoverflow.com/questions/48735373/angular-material-no-provider-for-matdialog-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!