¿Cómo agregar "clase" al elemento host?

190

No sé cómo agregar a mi componente <component></component>un atributo de clase dinámica , pero dentro de la plantilla html (component.html).

La única solución que encontré es modificar el elemento a través del elemento nativo "ElementRef". Esa solución parece un poco complicada para hacer algo que debería ser muy simple.

Otro problema es que CSS debe definirse fuera del alcance del componente, rompiendo la encapsulación del componente.

¿Hay una solución más simple? Algo así como <root [class]="..."> .... </ root>dentro de la plantilla.

lascarayf
fuente

Respuestas:

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(); 
  }
}

Ejemplo de Plunker

De esta manera, no necesita agregar el CSS fuera del componente. CSS como

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

funciona desde el interior del componente y el selector solo se aplica si la clase someClassse establece en el elemento host.

Günter Zöchbauer
fuente
Tuve que hacer el método someField = trueen ngOnInit()lugar de ngAfterViewInit(). No podría hacerlo funcionar de otra manera.
John
Hice un tenedor aquí que muestra la :hostparte real funcionando. ¿Dónde puedo obtener más información sobre el parámetro de host en el decorador @Component () (la sintaxis no me resulta obvia y la documentación de @Component no explica mucho ) u obtener más información sobre su HostBinding preferido (solo aparece como una interfaz en Angular2 sitio?)
The Red Pea
No sé mejores documentos, pero es sólo una forma diferente de hacer lo que puede hacer con@Input() @Output() @HostBinding() @HostListener() @ViewChild(ren)() @ContentChild(ren)()
Günter Zöchbauer
1
use un captador con un nombre diferente para el enlace del host que devuelve el valor invertido@HostBinding('class.xxx') get xxxclass(){ return !this.someField;}
Günter Zöchbauer
1
@YochaiAkoka no estoy seguro de a qué te refieres. No estoy al tanto de esta regla. Por lo general, menos es más, por lo que si puede evitar agregar elementos adicionales, entonces debe evitarlo.
Günter Zöchbauer
184

La respuesta de Günter es excelente (la pregunta es el atributo de clase dinámica ), pero pensé que agregaría solo para completar ...

Si está buscando una forma rápida y limpia de agregar una o más clases estáticas al elemento host de su componente (es decir, para fines de diseño de temas), puede hacer lo siguiente:

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

Y si usa una clase en la etiqueta de entrada, Angular fusionará las clases, es decir,

<my-component class="someClass2">
  I have both someClass1 & someClass2 applied to me
</my-component>
JoshuaDavid
fuente
1
Me encanta esto por simplicidad. Sin embargo, en mi caso, el elemento host está encapsulado con un atributo diferente, llamémoslo ngcontent_hosta cualquiera de los atributos en los elementos de mi plantilla , let's call those ngcontent_template , so if I put a style in the styleUrls` de mi componente, no afectarán al elemento host porque no afectarán ngcontent_host, ellos solo puede afectar elementos de plantilla; solo pueden afectar ngcontent_template. ¿Estoy equivocado? ¿Alguna sugerencia sobre esto? Supongo que siempre podría girarViewEncapsulation.None
The Red Pea
11
Otra forma es simplemente omitir la variable, @HostBinding('class.someClass') true;. Incluso puede hacer esto desde cualquier clase que extienda su componente.
adamdport
3
Para agregar varias clases, puede hacer host: {'[class]': '"class1 class2"'}
jbojcic
44
Si usa la {}variante host: es posible que desee establecer la use-host-property-decoratorconfiguración falseen tslint.json. De lo contrario, recibirá advertencias IDE. @adamdport Ese método ya no funciona (más). Usando Angular 5.2.2 en nuestra aplicación.
Ruud Voost
1
¿Soy solo yo, o la vieja forma parece mejor que la nueva? Estoy seguro de que tenían buenas razones para migrar, pero meh ...
aplastar el
13

Simplemente puede agregar @HostBinding('class') class = 'someClass';dentro de su clase @Component .

Ejemplo:

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

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

  constructor() {}      

  ngOnInit() {}
}
Mike D3ViD Tyson
fuente
1
La directiva className también se puede usar y es mejor evitar usarla classcomo un nombre de variable (ya que puede hacer referencia a ella y cambiarla más adelante). Ejemplo: @HostBinding('className') myTheme = 'theme-dark';.
CPHPython
0

Así es como lo hice (Angular 7):

En el componente, agregue una entrada:

@Input() componentClass: string = '';

Luego, en la plantilla HTML del componente, agregue algo como:

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

Y, por último, en la plantilla HTML donde instancia el componente:

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

Descargo de responsabilidad: soy bastante nuevo en Angular, ¡así que podría tener suerte aquí!

zippycoder
fuente
2
Ligeramente necro pero: esto no agrega la clase CSS al elemento host, que es el elemento para la <root>etiqueta, no nada que agregue a la plantilla del elemento.
millimoose