tutorial - typescript-o javascript moderno para criação de aplicações pdf




Estendendo o decorador de componentes com o decorador da classe base (4)

Após as versões mais recentes do Angular, a classe ComponentMetadata não está disponível conforme indicado por poucos membros aqui.

É assim que eu implementei o CustomComponent para fazê-lo funcionar:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
      let parentTarget = Object.getPrototypeOf(target.prototype).constructor;
      let parentAnnotations = Reflect.getOwnMetadata('annotations', parentTarget);

      let parentAnnotation = parentAnnotations[0];

      Object.keys(annotation).forEach(key => {
        parentAnnotation[key] = annotation[key];
      });
  };
}

Espero que ajude!

EDIT : o pedaço anterior do código, mesmo que funcione, substitui os metadados originais da classe estendida. Encontre abaixo uma versão aprimorada, permitindo que você tenha várias heranças e substituições sem modificar a classe base.

export function ExtendComponent(annotation: any) {
  return function (target: Function) {
    let currentTarget = target.prototype.constructor;
    let parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    let parentAnnotations = Reflect.getOwnMetadata('annotations', parentTarget);

    Reflect.defineMetadata('annotations', [Object.create(parentAnnotations[0])], currentTarget);
    let currentAnnotations = Reflect.getOwnMetadata('annotations', currentTarget);

    Object.keys(annotation).forEach(key => {
        currentAnnotations[0][key] = annotation[key];
    });
};

}

Eu tenho várias declarações de decorador de componentes que repito em cada componente, por exemplo:

@Component({
    moduleId: module.id,
    directives: [BootstrapInputDirective]
})

Como posso aplicar essas declarações a todos os meus componentes? Tentei criar uma classe base com esse decorador e estender outras classes com ele, mas as decorações da classe base não parecem se aplicar às classes derivadas.


Apenas no caso de você estar procurando pela função isPresent:

function isPresent(obj: any): boolean { return obj !== undefined && obj !== null; }


Você pode fornecer serviços globalmente em sua função de inicialização, como:

bootstrap(AppComponent, [HTTP_PROVIDERS, provide(SharedService, {useValue: sharedService})]);

onde sharedService é seu serviço importado.


@Component é um decorador. Isso significa que ele lida com a classe em que se aplica adicionando alguns dados de metadados, aproveitando a biblioteca reflect-metadata. Angular2 não procura metadados nas classes pai. Por esse motivo, não é possível usar decoradores nas classes principais.

Em relação à diretiva BootstrapInputDirective , você pode defini-la como uma plataforma. Dessa forma, você não precisaria incluí-lo sempre no atributo directives de seus componentes.

Aqui está uma amostra:

(...)
import {PLATFORM_DIRECTIVES} from 'angular2/core';

bootstrap(AppComponent, [
  provide(PLATFORM_DIRECTIVES, {useValue: [BootstrapInputDirective], multi:true})
]);

Editar

Sim, você pode criar seu próprio decorador para implementar isso. Aqui está uma amostra:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = annotation.parent;
    delete annotation.parent;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        annotation[key] = parentAnnotation[key];
      }
    });
    var metadata = new ComponentMetadata(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

O decorador CustomComponent será usado desta maneira:

@Component({
  template: `
    <div>Test</div>
  `
})
export class AbstractComponent {
}

@CustomComponent({
  selector: 'sub',
  parent: AbstractComponent
})
export class SubComponent extends AbstractComponent {
}

Observe que precisamos fornecer a classe pai como entrada do decorador, pois podemos descobrir essa classe pai dentro do decorador. Somente o protótipo dessa classe, mas os metadados, são aplicados na classe e não no protótipo associado por reflect-metadata.

Edit2

Graças à resposta de Nitzam, aqui está uma melhoria:

export function CustomComponent(annotation: any) {
  return function (target: Function) {
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);

    var parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key => {
      if (isPresent(parentAnnotation[key])) {
        annotation[key] = parentAnnotation[key];
      }
    });
    var metadata = new ComponentMetadata(annotation);

    Reflect.defineMetadata('annotations', [ metadata ], target);
  }
}

Não é necessário que um atributo parent faça referência à classe pai no decorador personalizado.

Veja este artigo: https://plnkr.co/edit/ks1iK41sIBFlYDb4aTHG?p=preview .

Veja esta pergunta:







angular