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.

Lascarayf
la source

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.

Günter Zöchbauer
la source
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>
JoshuaDavid
la source
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() {}
}
Mike D3ViD Tyson
la source
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
3

Si vous souhaitez ajouter une classe dynamique à votre élément hôte, vous pouvez combiner votre HostBindingavec un getter comme

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

Démo Stackblitz sur https://stackblitz.com/edit/angular-dynamic-hostbinding

Saksham
la source
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!

zippycoder
la source
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