Как добавить "класс" для размещения элемента?
Я не знаю, как добавить в свой компонент <component></component>
атрибут динамического класса, но внутри шаблона html (component.html).
Единственное решение, которое я нашел, - изменить элемент с помощью нативного элемента "ElementRef". Это решение кажется немного сложным, чтобы сделать что-то, что должно быть очень простым.
Другая проблема состоит в том, что CSS должен быть определен вне области компонента, нарушая инкапсуляцию компонента.
Есть ли более простое решение? Что-то вроде <root [class]="..."> .... </ root>
внутри шаблона.
11 ответов
@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();
}
}
Таким образом, вам не нужно добавлять CSS за пределы компонента. CSS как
:host(.someClass) {
background-color: red;
}
работает изнутри компонента и селектор применяется только если класс someClass
устанавливается на элементе хоста.
Методика, предложенная в этом ответе, устарела и больше не должна использоваться разработчиками Angular. Пожалуйста, смотрите предыдущий ответ для поддерживаемой опции.
Ответ Гюнтера великолепен (вопрос требует атрибута динамического класса), но я подумал, что добавлю только для полноты...
Если вы ищете быстрый и понятный способ добавления одного или нескольких статических классов к элементу host вашего компонента (т. Е. Для целей оформления тем), вы можете просто сделать:
@Component({
selector: 'my-component',
template: 'app-element',
host: {'class': 'someClass1'}
})
export class App implements OnInit {
...
}
И если вы используете класс в теге entry, Angular объединит классы, т.е.
<my-component class="someClass2">
I have both someClass1 & someClass2 applied to me
</my-component>
Вы можете просто добавить @HostBinding('class') class = 'someClass';
внутри вашего класса @Component.
Пример:
@Component({
selector: 'body',
template: 'app-element'
})
export class App implements OnInit {
@HostBinding('class') class = 'someClass';
constructor() {}
ngOnInit() {}
}
Если вы хотите добавить динамический класс к элементу хоста, вы можете объединить свои HostBinding
с геттером как
@HostBinding('class') get class() {
return aComponentVariable
}
Демо Stackblitz на https://stackblitz.com/edit/angular-dynamic-hostbinding
Другая проблема заключается в том, что CSS должен быть определен вне области действия компонента, что нарушает инкапсуляцию компонента.
Это неправда. С помощью scss (SASS) вы можете легко стилизовать компонент (сам; хост) следующим образом:
:host {
display: block;
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
visibility: hidden;
&.someClass {
visibility: visible;
}
}
Таким образом, инкапсуляция не нарушается.
В дополнение к ответу @JoshuaDavid есть еще один способ определить статический класс, который работает на angular v8, когда я пытался (может также работать в более старых версиях):
@Component({
selector: "my-component.someClass1.someClass2",
...
})
который будет генерировать следующий вывод:
<my-component class="someClass1 someClass2">
...
</my-component>
вы также можете просто использовать этот способ:
@Component({
selector: ".someClass1.someClass2",
...
})
который будет генерировать следующий вывод:
<div class="someClass1 someClass2">
...
</div>
Для ситуации с несколькими классами, как упоминалось выше @jbojcic, вы можете использовать:
хост: {класс: 'A B C'}
вот что я сделал:
import { Component, Attribute, HostBinding } from "@angular/core";
@Component({
selector: "selector-el",
template: ...
})
export class MyComponent {
@HostBinding('class') get classAttribute(): string {
let defaultClasses = 'selector-el-class';
return defaultClasses + ' ' + this.classNames;
}
constructor(
@Attribute('class') public classNames: string
) { }
}
Не нашел ответов о подходе Renderer2 .
Вот что я использовал, например:
constructor(
private readonly elementRef: ElementRef,
private readonly renderer: Renderer2
) { }
@Input()
set disabled(disabled: boolean) {
if (disabled) {
this.renderer.addClass(this.elementRef.nativeElement, 'disabled');
}
}
или внутриngOnInit
ngOnInit(): void {
if (this.something.disabled) {
this.renderer.addClass(this.elementRef.nativeElement, 'disabled');
}
}
Вот как я это сделал (Angular 7):
В компонент добавьте вход:
@Input() componentClass: string = '';
Затем в HTML-шаблон компонента добавьте что-то вроде:
<div [ngClass]="componentClass">...</div>
И, наконец, в шаблоне HTML, где вы создаете экземпляр компонента:
<root componentClass="someclass someotherclass">...</root>
Отказ от ответственности: я довольно новичок в Angular, так что, возможно, мне просто повезло здесь!
Когда у вас есть несколько классов, привязанных к хосту, я обнаружил, что следующее использованиеHostBinding
геттер наиболее удобен:
@Component({ ... })
export class MyComponent {
@Input()
theme: 'success' | 'error';
@HostBinding('class')
get classes(): Record<string, boolean> {
return {
'my-component': true,
'my-component-success-theme': this.theme == 'success',
'my-component-error-theme': this.theme == 'error'
}
}
}
Даже для тривиальных привязок классов, которые не имеют соответствующей логики, это хороший способ управлять всеми вашими базовыми классами в одном месте.
@Component({ ... })
export class MyComponent {
@HostBinding('class')
get classes(): Record<string, boolean> {
return {
'my-component': true,
'my-component-modifier': true
}
}
}