Como adicionar "classe" ao elemento host?

190

Não sei como adicionar ao meu componente <component></component>um atributo de classe dinâmica, mas dentro do modelo html (component.html).

A única solução que encontrei é modificar o item via elemento nativo "ElementRef". Essa solução parece um pouco complicada para fazer algo que deve ser muito simples.

Outro problema é que o CSS deve ser definido fora do escopo do componente, quebrando o encapsulamento do componente.

Existe uma solução mais simples? Algo como <root [class]="..."> .... </ root>dentro do modelo.

lascarayf
fonte

Respostas:

296
@Component({
   selector: 'body',
   template: 'app-element',
   // prefer decorators (see below)
   // host:     {'[class.someClass]':'someField'}
})
export class App implements OnInit {
  constructor(private cdRef:ChangeDetectorRef) {}

  someField: boolean = false;
  // alternatively also the host parameter in the @Component()` decorator can be used
  @HostBinding('class.someClass') someField: boolean = false;

  ngOnInit() {
    this.someField = true; // set class `someClass` on `<body>`
    //this.cdRef.detectChanges(); 
  }
}

Exemplo de plunker

Dessa forma, você não precisa adicionar o CSS fora do componente. CSS como

:host(.someClass) {
  background-color: red;
}

funciona a partir do interior do componente e o seletor é aplicado apenas se a classe someClassestiver configurada no elemento host.

Günter Zöchbauer
fonte
Eu tive que fazer o someField = trueem ngOnInit()-method em vez de ngAfterViewInit(). Eu não poderia fazê-lo funcionar de outra maneira.
John John
Fiz um garfo aqui que mostra a :hostpeça real funcionando. Onde posso aprender mais sobre o parâmetro host no decorador @Component () (a sintaxe não é óbvia para mim e a documentação do @Component não explica muito ) ou saber mais sobre o HostBinding preferido (ele é listado apenas como uma interface no Angular2 site?)
The Red Pea
Eu não sei melhores docs, mas é apenas uma maneira diferente de fazer o que você pode fazer com@Input() @Output() @HostBinding() @HostListener() @ViewChild(ren)() @ContentChild(ren)()
Günter Zöchbauer
1
usar um getter com um nome diferente para a ligação que devolve o valor invertido hospedeiro@HostBinding('class.xxx') get xxxclass(){ return !this.someField;}
Günter Zöchbauer
1
@YochaiAkoka não sabe ao que se refere. Eu não estou ciente desta regra. Menos é geralmente mais, portanto, se você pode evitar adicionar elementos adicionais, evite-o.
Günter Zöchbauer 13/10/19
184

A resposta de Günter é ótima (a pergunta está pedindo atributo de classe dinâmica ), mas pensei em adicionar apenas por estar completo ...

Se você está procurando uma maneira rápida e limpa de adicionar uma ou mais classes estáticas ao elemento host do seu componente (por exemplo, para fins de estilo de tema), basta fazer o seguinte:

@Component({
   selector: 'my-component',
   template: 'app-element',
   host: {'class': 'someClass1'}
})
export class App implements OnInit {
...
}

E se você usar uma classe na tag de entrada, o Angular mesclará as classes, ou seja,

<my-component class="someClass2">
  I have both someClass1 & someClass2 applied to me
</my-component>
JoshuaDavid
fonte
1
Amo isso pela simplicidade. No entanto, no meu caso, o elemento host é encapsulado com um atributo diferente, vamos chamá-lo ngcontent_hostde qualquer um dos atributos nos elementos do meu modelo , let's call those ngcontent_template , so if I put a style in the styleUrls` do meu componente, eles não afetarão o elemento host porque não afetarão ngcontent_host, eles pode afetar apenas elementos do modelo; eles só podem afetar ngcontent_template. Estou enganado? Alguma sugestão sobre isso? Eu acho que sempre poderia virarViewEncapsulation.None
The Red Pea
11
Outra maneira é simplesmente pular a variável @HostBinding('class.someClass') true;,. Você pode fazer isso de qualquer classe que seu componente estender.
Adamdport 8/17
3
Para adicionar várias classes, você pode fazer o host: {'[class]': '"class1 class2"'}
jbojcic
4
Se você usar a {}variante host :, poderá definir a use-host-property-decoratorconfiguração como falsein tslint.json. Caso contrário, você receberá avisos do IDE. @adamdport Esse método não funciona (mais). Usando Angular 5.2.2 em nosso aplicativo.
Ruud Voost
1
Sou só eu, ou o jeito antigo parece melhor do que o novo? Tenho certeza que eles tinham boas razões para migrar, mas meh ...
crush
13

Você pode simplesmente adicionar @HostBinding('class') class = 'someClass';dentro da sua classe @Component .

Exemplo:

@Component({
   selector: 'body',
   template: 'app-element'       
})
export class App implements OnInit {

  @HostBinding('class') class = 'someClass';

  constructor() {}      

  ngOnInit() {}
}
Mike D3ViD Tyson
fonte
1
A diretiva className também pode ser usada e é melhor evitar o uso classcomo um nome de variável (pois você pode fazer referência a ela e alterá-la posteriormente). Exemplo: @HostBinding('className') myTheme = 'theme-dark';.
CPHPython 16/01
3

Se você deseja adicionar uma classe dinâmica ao seu elemento host, você pode combiná-lo HostBindingcom um getter como

@HostBinding('class') get class() {
    return aComponentVariable
}

Demonstração do Stackblitz em https://stackblitz.com/edit/angular-dynamic-hostbinding

Saksham
fonte
0

Aqui está como eu fiz (Angular 7):

No componente, adicione uma entrada:

@Input() componentClass: string = '';

Em seguida, no modelo HTML do componente, adicione algo como:

<div [ngClass]="componentClass">...</div>

E, finalmente, no modelo HTML em que você instala o componente:

<root componentClass="someclass someotherclass">...</root>

Exoneração de responsabilidade: Eu sou bastante novo no Angular, então talvez eu esteja tendo sorte aqui!

zippycoder
fonte
2
Ligeiramente necro mas: isso não adiciona a classe CSS ao elemento host - que é o elemento para a <root>tag, e não qualquer coisa que você adiciona ao modelo do elemento.
millimoose