NullInjectorError: 没有 MatDialogRef 的提供程序

我不能像文档中描述的那样注入 MatDialogRef: https://material.angular.io/components/dialog/overview

当我试着去做的时候,我犯了一个错误:

StaticInjectorError [ MatDialogRef ] : StaticInjectorError [ MatDialogRef ] : NullInjectorError: 没有 MatDialogRef 提供程序!

应用程序模块

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';


import {
MatInputModule,
MatDialogModule,
MatProgressSpinnerModule,
MatButtonModule,
MatDialog,
MatDialogRef
} from '@angular/material';


import { ApiModule } from '../api/api.module';
import { RoutingModule } from '../routing/routing.module';


import { RegistrationComponent } from './components/registration.component';
import { LoginComponent } from './components/login.component';


import { AccountService } from './services/account.service';


@NgModule({
imports: [
BrowserModule,
MatInputModule,
MatDialogModule,
MatProgressSpinnerModule,
MatButtonModule,
FormsModule,
RoutingModule,
ApiModule
],
declarations: [
RegistrationComponent,
LoginComponent
],
entryComponents: [
LoginComponent,
RegistrationComponent
],
providers: [
AccountService,
MatDialog,
MatDialogRef
]
})
export class AccountModule {}

家庭,组件

import { Component } from '@angular/core';


import { MatDialog } from '@angular/material';
import { RegistrationComponent } from '../account/components/registration.component';


@Component({
moduleId: module.id.replace('compiled', 'app'),
templateUrl: 'home.component.html'
})
export class HomeComponent
{
constructor(private modalService: MatDialog) {}


public openModal() : void
{
let dialog = this.modalService.open(RegistrationComponent, {});
}
}

Registration.Component. ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { MatDialogRef } from '@angular/material/dialog';


import { User } from '../../../models/domain/User';
import { ApiUserService } from '../../api/entity-services/user.service';
import { AuthService } from '../../auth/auth.service';
import { AccountService } from '../services/account.service'


@Component({
selector: 'registration-component',
templateUrl: 'app/modules/account/templates/registration.component.html'
})
export class RegistrationComponent
{
public user :User = new User();


public errorMessage :string;


public isLoading :boolean;


constructor
(
private userService :ApiUserService,
private authService :AuthService,
private accountService :AccountService,
private router :Router,
public dialogRef :MatDialogRef<RegistrationComponent>
)
{
this.isLoading = false;
}


public onSubmit(e) :void
{
e.preventDefault();
this.isLoading = true;


this.userService
.Create(this.user)
.subscribe(
user =>
{
this.user.id = user.id;
this.user.login = user.login;




this.authService
.Login(this.user)
.subscribe(
token =>
{
this.accountService.Load()
.subscribe(
account =>
{
this.user = account;
this.isLoading = false;
this.dialogRef.close();


let redirectRoute = account.activeScopeId
? `/scope/${account.activeScopeId}`
: '/scope-list/';


this.router.navigate([redirectRoute]);
},
error => this.errorMessage = <any>error
);
},
error => this.errorMessage = <any>error
);
},
error => this.errorMessage = <any>error
);
}
}

162175 次浏览

It could be due to you not including a Web Animations API polyfill which is required for Angular animations to work since it relies on the API.

Here's a caniuse for the browsers that support it natively. Currently only Chrome, Firefox and Opera support the Web Animations API.

Anyway, you have to follow these steps to get a polyfill:

  1. In the terminal, type the following in your console:

    npm install web-animations-js
    
  2. Once you have finished installing, uncomment the line for Angular Animations in polyfills.ts (or add it if it's not there):

    import 'web-animations-js'; // Uncomment this line
    

Alternatively, you can try importing the modules from the separate endpoints, like so:

From:

import { MatButtonModule, MatDialogModule } from '@angular/material';

To:

import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';

Thanks to the @Edric, i'v solved the problem by importing MatDialogModule, MatDialog and MatDialogRef from @angular/material/dialog instead of @angular/material

  • In your module: importing only MatDialogModule from angular/material is sufficient. Not required to import and provide: MatDialogRef
  • In your code where DialogComponent import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
  • The above are the steps that I have followed. Not sure why you need to import it from the Dialog
  • But, could you please clarify which selector you have used in your html/template? If you have used the "registration-component" in your template, that could be the reason why you would get this error. I tried out the exact same example out of the Material guide. I accidentally used the 'dialog-overview-example-dialog' instead of the 'dialog-overview-example'. = I got the same error you have got.

I had this error when adding dialogs to a service to be shared in many components. Just to clarify, the error wasn't present in the application before moving dialogs to the service. The solution was to include a custom provider MatDialogRef in the main module

  import { DialogService } from './services/dialog.service';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
...
imports: [
...
MatDialogModule
],
providers: [
{
provide: MatDialogRef,
useValue: {}
},
DialogService
],
...

With this provider the service worked as a singleton with my dialogs to be shared and the provider error was gone.

This error can be caused by injecting MatDialogRef in the component calling MatDialog::open rather than in the component that is passed to the open method. The component passed to the MatDialog open method should have MatDialogRef injected in its constructor as done in the example.

@Component({
selector: 'dialog-overview-example-dialog',
templateUrl: 'dialog-overview-example-dialog.html',
})
export class DialogOverviewExampleDialog {


constructor(
public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
@Inject(MAT_DIALOG_DATA) public data: DialogData) {}


onNoClick(): void {
this.dialogRef.close();
}


}

For me the problem was that I had added my Dialog component to some other HTML Template just to test it. Once I removed it, the error in OP went away and it just worked.

For example you are using app-checkout

It could be happen if you use a component in both 'dialog' and 'normal' way add app-checkout in normal html file.

Solution 1: remove <app-checkout> </app-checkout>if you dont need import it in normal way in html file

Solution 2 using in both dialog and html file. Instead of this:

// ... something have selector: "app-checkout",
constructor(
public dialogRef: MatDialogRef<CheckoutComponent>,
@Inject(MAT_DIALOG_DATA) public dialogData: any
) {}

you need to inject it (to make it optional inject):

this way:


constructor(
// only need the @Optional() before the public dialogRef
@Optional() public dialogRef: MatDialogRef<CheckoutComponent>,
@Inject(MAT_DIALOG_DATA) public dialogData: any
) {


}


or this way:

// ... the same above
private dialogRef = null;
private dialogData;
constructor(private injector: Injector) {
this.dialogRef = this.injector.get(MatDialogRef, null);
this.dialogData = this.injector.get(MAT_DIALOG_DATA, null);
}

Additionally to all of the above, You may also get this error if you have references to the Component selector in any of the template files in your app. MatDialog Components should only be invoked by the MatDialog.dialog.open() method and not through component selector

Unfortunately, the same error message may be thrown for many reasons.

I had this Error and fixed it what you have to do is

  1. check if you inserted import statement in the typescript file like this

    import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";

  2. check the constructor

      constructor(@Optional() public dialogRef: MatDialogRef<GadgetAuthMessagesComponent>, @Inject(MAT_DIALOG_DATA) public message: string){ }
    
  3. now go to module .ts and check the imports

    import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
    
  4. in module.ts we need to put MatDialogModule name under imports array

    MatDialogModule

  5. now that's done finally we have to update the providers array

      providers:
[{
provide: 'gadget-mlt',
useValue: GadgetMltComponent,
},
{provide:MatDialogRef , useValue:{} },


{ provide: MAT_DIALOG_DATA, useValue: {} }


],

Now It should work , Hope this Helps someone !

Just add @Optional() before your dialogRef declaration.

For example:

constructor(
@Optional() public dialogRef: MatDialogRef<yourDialogComponentName>
) {
}

the imported paths in the component.ts and in spec.ts must be identical

for example:

// in the component and spec files
import { MatDialogRef } from '@angular/material/dialog';

or

// in the component and spec files
import { MatDialogRef } from '@angular/material';

Apparently everything was fine in my code. The problem was that while developing, I had a temporal route for my modal component so I could view it like a any other regular component/view. In the component, I had a button that triggers opening itself in a modal so I can test it how it looks when actually opened.

So I moved the code that opens the Dialog to another component and it seems to solve the issue.

in angular 12 in used "@Optional()" before inject mat dialog like below:

 @Optional() @Inject(MAT_DIALOG_DATA) public data:any

and in main app module added some code like below:

  providers: [
{
provide: MatDialogRef,
useValue: {}
}
],

best Regards.

This error is generally caused by not providing the required modules. Import the outer module to your module where you are using the outer modules component. That will probably solve the problem.

Adding MatDialogModule to my app.module.ts - solved my problem.

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

I had this issue a couple of times and in my case, I was trying to implement a modal with optional data passed to it. My solution was to add this piece of code to the parent module that implements the dialog/modal I was trying to display.

I tested this solution in case you implement the providers inside the app.module.ts (Grand-parent, etc.), and it will still work.

// direct.parent.module.ts


// Import statements
import{...} from '';
import{<YOUR_COMPONENT>} from 'YOUR_COMPONENT_PATH';
...


@NgModule({
declarations: [..],
imports:[..],
providers: [ // <== This is the key that made it work
{
provide: MatDialogRef,
useValue: {}
},
{ provide: MAT_DIALOG_DATA, useValue: {} }, // <== I had to add this too
<YOUR_COMPONENT> // My Component
],
})


export class DirectParentModule { }

Don't provide dummy MatDialogRef or you will be unable to use it within the dialog component. For instance if you try to close the modal material will try to call .close() on {} because of the provide: MatDialogRef, useValue: {} and throws.

Take a look at your module (answers above) & imports.

In my case, I unintentionally imported Dialog from cdk instead of MatDialog from material.

import { Dialog } from "@angular/cdk/dialog"; // wrong
...
constructor(private dialog: Dialog) {}
import { MatDialog } from "@angular/material/dialog"; // good
...
constructor(private dialog: MatDialog) {}