#angular
#angular
Вопрос:
В настоящее время я выполняю некоторый рефакторинг приложения, а именно некоторых форм. Я заметил, что все они были похожи. До рефакторинга они работали, но когда я добавил новый родительский класс и расширил его, я начал получать эту ошибку для дочерних компонентов:
ОШИБКА: фабрика компонентов не найдена для SaveCategoryComponent. Вы добавили его в @NgModule.Входные компоненты?
Мой родительский компонент выглядит следующим образом:
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;
},
);
}
}
}
Как вы можете видеть, он ищет некоторые данные, которые в данном случае BaseModel
:
export interface BaseModel {
id: string | number;
}
И моя категория выглядит примерно так:
import { BaseModel } from './base-model';
export class Category implements BaseModel {
id: string;
name: string;
image: string;
active: boolean;
}
Все они компилируются и выглядят нормально.
Тогда у меня есть дочерний элемент, который выглядит следующим образом:
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 {}
(Я удалил любой код из модуля, который вообще не связан)
У меня также есть созданная мной служба диалога (которая работала до того, как я создал родительский:
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);
}
}
И затем в моем основном компоненте я делаю что-то вроде этого:
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);
}
});
}
Все это работало до того, как я создал SaveComponent
. Как только я пытаюсь его расширить, я получаю ошибку выше. Я знаю, что компонент определен в entryComponents в общем модуле, поэтому я понятия не имею, на что он жалуется.
Кто-нибудь может помочь?
Комментарии:
1. Вы также пытались добавить
SaveComponent
в массив входных компонентов? В качестве приветствия, я вижу, как это может потребоваться из-за ошибки и замаскировано в сообщении об ошибке. То же самое для, возможно, любой комбинацииexports
иdeclarations
2. Я не могу, потому что у него нет
@component
декоратора:(3. Хм, я где-то читал (не спрашивайте меня где), что при наследовании компонентов
@Component
декораторы объединяются вместе (поля дочернего элемента переопределяют поля родительского).). Я думаю, вы можете безопасно добавить этот декоратор и переопределить значения, возможно, это даже требуется для его правильной работы.4. Я попробую, но я уверен, что вы не сможете 🙂 держитесь крепче, и я сообщу об этом!
5. Я погуглил «наследование компонентов Angular», и все первые 3 релевантных результата используют
@Component
декоратор для своего базового компонента, как здесь . Они предоставляют фиктивные шаблоны и стили и переопределяют их в дочерних элементах. Надеюсь, это как-то связано с вашей проблемой
Ответ №1:
Я потратил на это часы и не смог это исправить. Затем я нашел сообщение, в котором упоминалось, что entryComponents не используются в Angular 9, поэтому я обновил все свои пакеты, следуя этому руководству:
Когда я это сделал, я начал получать новые ошибки. Я прошел через все это, и в конце концов обнаружил, что мой AppModule
требуется как FormsModule
, так и ReactiveFormsModule
для импорта. Когда я это сделал, все начало работать.
В интересах науки я решил вернуться к своей исходной ветке и попробовать импортировать эти модули, чтобы посмотреть, устранило ли это проблему в 8.2. Этого не произошло, поэтому я понятия не имею, как это исправить. Единственным решением, которое я нашел, было обновление:(