Общий компонент Angular 8.2, расширяющий другой компонент, не выдает заводскую ошибку компонента

#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, поэтому я обновил все свои пакеты, следуя этому руководству:

https://update.angular.io/

Когда я это сделал, я начал получать новые ошибки. Я прошел через все это, и в конце концов обнаружил, что мой AppModule требуется как FormsModule , так и ReactiveFormsModule для импорта. Когда я это сделал, все начало работать.

В интересах науки я решил вернуться к своей исходной ветке и попробовать импортировать эти модули, чтобы посмотреть, устранило ли это проблему в 8.2. Этого не произошло, поэтому я понятия не имею, как это исправить. Единственным решением, которое я нашел, было обновление:(