Comment ajouter une «classe» à l'élément hôte?


190

Je ne sais pas comment ajouter à mon composant <component></component>un attribut de classe dynamique mais à l'intérieur du template html (component.html).

La seule solution que j'ai trouvée est de modifier l'élément via l'élément natif "ElementRef". Cette solution semble un peu compliquée pour faire quelque chose qui devrait être très simple.

Un autre problème est que CSS doit être défini en dehors de la portée des composants, ce qui rompt l'encapsulation des composants.

Existe-t-il une solution plus simple? Quelque chose comme <root [class]="..."> .... </ root>à l'intérieur du modèle.

Réponses:


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

Exemple de Plunker

De cette façon, vous n'avez pas besoin d'ajouter le CSS en dehors du composant. CSS comme

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

fonctionne de l'intérieur du composant et le sélecteur n'est appliqué que si la classe someClassest définie sur l'élément hôte.


J'ai dû faire la méthode someField = truein ngOnInit()-met au lieu de ngAfterViewInit(). Je ne pourrais pas le faire fonctionner autrement.
John

Fabriqué ici une fourche qui montre le fonctionnement réel de la :hostpièce. Où puis-je en savoir plus sur les paramètres d'hôte dans le décorateur @Component () (la syntaxe n'est pas évidente pour moi, et la documentation @Component n'explique pas grand-chose ) ou en savoir plus sur votre HostBinding préféré (il n'est répertorié que comme interface sur Site Angular2?)
The Red Pea

Je ne connais pas de meilleurs documents, mais c'est juste une façon différente de faire ce que vous pouvez faire avec@Input() @Output() @HostBinding() @HostListener() @ViewChild(ren)() @ContentChild(ren)()
Günter Zöchbauer

1
utilisez un getter avec un nom différent pour la liaison hôte qui renvoie la valeur inversée@HostBinding('class.xxx') get xxxclass(){ return !this.someField;}
Günter Zöchbauer

1
@YochaiAkoka ne sait pas à quoi vous faites référence Je ne connais pas cette règle. Moins est généralement plus, donc si vous pouvez éviter d'ajouter des éléments supplémentaires, vous devez l'éviter.
Günter Zöchbauer

184

La réponse de Günter est excellente (la question demande un attribut de classe dynamique ) mais j'ai pensé que j'ajouterais juste pour être complet ...

Si vous recherchez un moyen rapide et propre d'ajouter une ou plusieurs classes statiques à l'élément hôte de votre composant (c'est-à-dire à des fins de style de thème), vous pouvez simplement faire:

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

Et si vous utilisez une classe sur la balise d'entrée, Angular fusionnera les classes, c'est-à-dire,

<my-component class="someClass2">
  I have both someClass1 & someClass2 applied to me
</my-component>

1
J'adore ça pour la simplicité. Cependant, dans mon cas, l'élément hôte est encapsulé avec un attribut différent, appelons-le ngcontent_hostque n'importe lequel des attributs sur les éléments de mon modèle , let's call those ngcontent_template , so if I put a style in the styleUrls` de mon composant, ils n'affecteront pas l'élément hôte car ils n'affecteront pas ngcontent_host, ils ne peut affecter que les éléments du modèle; ils ne peuvent qu'affecter ngcontent_template. Est-ce que je me trompe? Des suggestions à ce sujet? Je suppose que je pourrais toujours tournerViewEncapsulation.None
The Red Pea

11
Une autre façon est de sauter la variable @HostBinding('class.someClass') true;. Vous pouvez même le faire à partir de n'importe quelle classe étendue par votre composant.
adamdport

3
Pour ajouter plusieurs classes, vous pouvez créer l'hôte: {'[class]': '"class1 class2"'}
jbojcic

4
Si vous utilisez la {}variante hôte :, vous souhaiterez peut-être définir le use-host-property-decoratorparamètre sur falsein tslint.json. Sinon, vous recevrez des avertissements IDE. @adamdport Cette méthode ne fonctionne pas (plus). Utilisation d'Angular 5.2.2 dans notre application.
Ruud Voost

1
Est-ce juste moi, ou est-ce que l'ancienne méthode semble meilleure que la nouvelle? Je suis sûr qu'ils avaient de bonnes raisons de migrer, mais moi ...
écraser le

13

Vous pouvez simplement ajouter @HostBinding('class') class = 'someClass';dans votre classe @Component .

Exemple:

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

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

  constructor() {}      

  ngOnInit() {}
}

1
La directive className peut également être utilisée et il est préférable d'éviter de l'utiliser classcomme nom de variable (car vous pouvez la référencer et la modifier ultérieurement). Exemple: @HostBinding('className') myTheme = 'theme-dark';.
CPHPython


0

Voici comment je l'ai fait (Angular 7):

Dans le composant, ajoutez une entrée:

@Input() componentClass: string = '';

Ensuite, dans le modèle HTML du composant, ajoutez quelque chose comme:

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

Et enfin dans le modèle HTML où vous installez le composant:

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

Avertissement: je suis assez nouveau dans Angular, donc je vais peut-être avoir de la chance ici!


2
Légèrement nécro mais: cela n'ajoute pas la classe CSS à l'élément hôte - qui est l'élément de la <root>balise, pas tout ce que vous ajoutez dans le modèle de l'élément.
millimoose
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.