Reputation: 13367
I am currently doing some refactoring on an application, namely some forms. I noticed they were all similar. Before the refactor they were working, but when I added the new parent class and extended it, I started getting this error for the child components:
ERROR Error: No component factory found for SaveCategoryComponent. Did you add it to @NgModule.entryComponents?
My parent component looks like this:
import { OnInit, Inject } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { BaseModel, Attempt } from '@models';
import { NotificationService } from 'src/app/_shared/notification/notification.service';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { Observable } from 'rxjs';
export class SaveComponent implements OnInit {
public formGroup: FormGroup;
public submitted: boolean;
public notifications: object;
public isEditing: boolean;
// convenience getter for easy access to form fields
get f() {
return this.formGroup.controls;
}
constructor(
@Inject(MAT_DIALOG_DATA) public model: BaseModel,
public dialogRef: MatDialogRef<any>,
public notificationService: NotificationService,
) {}
ngOnInit(): void {
this.isEditing = !!this.model.id;
}
public onSave(callback: (model: any) => Observable<any>) {
this.submitted = true;
if (this.formGroup.valid) {
callback(this.formGroup.value).subscribe(
(response: Attempt<BaseModel>) => {
if (response.failure) {
this.notificationService.show(`${response.error.message}`, 'danger');
} else {
this.notificationService.show(`Successfully saved your category.`, 'success');
this.formGroup.reset();
}
this.submitted = false;
this.dialogRef.close(response.result);
},
() => {
this.submitted = false;
},
);
}
}
}
As you can see, it is looking for some data which in this case is BaseModel
:
export interface BaseModel {
id: string | number;
}
And my category looks like this:
import { BaseModel } from './base-model';
export class Category implements BaseModel {
id: string;
name: string;
image: string;
active: boolean;
}
Those all compile and look fine. Then I have the child which looks like this:
import { Component, OnInit, Inject } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { SaveComponent } from '../save.component';
import { Category } from '@models';
import { CategoryService } from '@services';
import { NotificationService } from '../../notification/notification.service';
@Component({
selector: 'app-save-category',
templateUrl: './save-category.component.html',
styleUrls: ['./save-category.component.scss'],
})
export class SaveCategoryComponent extends SaveComponent implements OnInit {
constructor(
@Inject(MAT_DIALOG_DATA) public model: Category,
public dialogRef: MatDialogRef<SaveCategoryComponent>,
public notificationService: NotificationService,
private formBuilder: FormBuilder,
private categoryService: CategoryService,
) {
super(model, dialogRef, notificationService);
}
ngOnInit(): void {
this.formGroup = this.formBuilder.group({
id: [this.model.id, Validators.required],
name: [this.model.name, Validators.required],
image: [this.model.image],
active: [this.model.active],
});
super.ngOnInit();
}
public save() {
const method = this.isEditing ? 'update' : 'create';
this.onSave(this.categoryService[method]);
}
}
This is part of my shared module, and is declared, exported and added as an entryComponent:
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
RouterModule,
FormsModule,
MatAutocompleteModule,
MatButtonModule,
MatCardModule,
MatDialogModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatRadioModule,
],
declarations: [
AlertDialogComponent,
ConfirmationDialogComponent,
SaveBrandComponent,
SaveCategoryComponent,
],
exports: [
AlertDialogComponent,
ConfirmationDialogComponent,
SaveBrandComponent,
SaveCategoryComponent,
],
providers: [DecimalPipe],
entryComponents: [
NotificationComponent,
UploadImagesComponent,
AlertDialogComponent,
ConfirmationDialogComponent,
SaveBrandComponent,
SaveCategoryComponent,
],
})
export class SharedModule {}
(I have removed any code from the module that isn't related at all) I also have a dialog service I created (which was working before I created the parent:
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
@Injectable({
providedIn: 'root',
})
export class DialogService {
constructor(private dialog: MatDialog) {}
public open(component: any, model: any): MatDialogRef<any> {
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.data = model;
return this.dialog.open(component, dialogConfig);
}
}
And then in my main component, I do something like this:
openEditModal(model: Category) {
const modalRef = this.dialogService.open(SaveCategoryComponent, model);
modalRef.afterClosed().subscribe((result: Category) => {
if (result) {
this.updateItem(result);
this.notificationSvc.show('You have successfully updated ' + result.name);
}
});
}
All this was working before I created the SaveComponent
. As soon as I try to extend it, I get the error above. I know the component is defined in entryComponents in the shared module, so I have no idea what it's complaining about.
Can anyone help?
Upvotes: 1
Views: 530
Reputation: 13367
I spent hours on this and could not fix it. Then I found a post that mentioned that entryComponents are not used in Angular 9, so I updated all my packages following this guide:
When I did this, I started getting new errors.
I went through it all and eventually I found that my AppModule
required both FormsModule
and ReactiveFormsModule
to be imported. When I did this, everything started working.
In the interest of science, I decided to go back to my original branch and try importing those modules to see if that fixed the issue in 8.2. It did not, so I have no idea how to fix it there. The only solution I found was upgrading :(
Upvotes: 1