es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Existe alguna forma de declarar un componente abstracto en Angular para que pueda ser utilizado en una plantilla?

Me gustaría crear un componente abstracto en mi aplicación Angular que tenga una plantilla que pueda ser reutilizada por mis componentes que extienden el componente abstracto. A continuación se muestra un ejemplo sencillo de lo que estoy tratando de hacer:

@Component({
  selector: 'app-abstract',
  templateUrl: '<ng-content></ng-content> {{ title }} Component',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export abstract class AbstractComponent implements OnInit {

title: string;  

public ngOnInit(): void {
    this.methodDefinedByExtenders();
  }

protected abstract methodDefinedByExtenders();
}
@Component({
  selector: 'app-extender-one',
  templateUrl: '<app-abstract>This is the <app-abstract></app-abstract></app-abstract>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExtenderOneComponent extends AbstractComponent {
  protected methodDefinedByExtenders(): void { 
    this.title = 'Cool Extender One'; 
  };
}
@NgModule({
  declarations: [
    AbstractComponent --> esto da un error,
    ExtenderOneComponent
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

La idea aquí es que la plantilla de ExtenderOne mostraría ‘This is the Cool Extender One Component’ utilizando el campo title y el gancho ngOnInit de su padre, AbstractComponent. El problema aquí es que obtengo el siguiente error:

Type 'typeof AbstractComponent' is not assignable to type 'Type<any>'.
    Cannot assign an abstract constructor type to a non-abstract constructor type.

Realmente me gustaría poder aprovechar el uso de la plantilla del AbstractComponent para envolver todos mis componentes que extienden AbstractComponent en una plantilla común. Sé que puedo eliminar AbstractComponent de mis declaraciones y seguir utilizándolo en el archivo .ts, pero reutilizar la plantilla nos ahorraría mucho tiempo de escritura. ¡Gracias!

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución:

    El mensaje de error indica que AbstractComponent es un constructor abstracto y no puede ser asignado a un tipo de constructor no abstracto. La solución a este problema es declarar tu AbstractComponent como una clase abstracta para que no pueda ser instanciada por sí misma.

    export abstract class AbstractComponent implements OnInit {
    
      title: string;
    
      ngOnInit(): void {
        this.methodDefinedByExtenders();
      }
    
      protected abstract methodDefinedByExtenders(): void ;
    }
    

    Luego, necesitas modificar tu NgModule para excluir AbstractComponent de tu array de declaraciones y agregar AbstractComponent como un proveedor con un valor nulo. Esto permite que el componente sea inyectado en sus extendidos pero asegura que no pueda ser instanciado en sí mismo.

    @NgModule({
      declarations: [
        ExtenderOneComponent
      ],
      providers: [{
        provide: AbstractComponent,
        useValue: null
      }],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    Ahora, puedes usar la plantilla de AbstractComponent en tu ExtenderOneComponent al definir el selector en tu ExtenderOneComponent para usar el selector de tu AbstractComponent.

    @Component({
      selector: 'app-extender-one',
      template: '<app-abstract>Este es el Componente {{ title }}</app-abstract>',
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class ExtenderOneComponent extends AbstractComponent {
      protected methodDefinedByExtenders(): void { this.title = 'Extensor Uno Genial'; };
    }
    

    ¡Eso es todo! Ahora tu ExtenderOneComponent puede usar la plantilla de tu AbstractComponent.

Comments are closed.