Как добавить «класс» к элементу хоста?


190

Я не знаю, как добавить к моему компоненту атрибут <component></component>динамического класса, но внутри шаблона html (component.html).

Единственное решение, которое я нашел, это изменить элемент с помощью нативного элемента "ElementRef". Это решение кажется немного сложным, чтобы сделать что-то, что должно быть очень простым.

Другая проблема заключается в том, что CSS должен быть определен вне области компонента, нарушая инкапсуляцию компонента.

Есть ли более простое решение? Что-то вроде <root [class]="..."> .... </ root>внутри шаблона.

Ответы:


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

Пример плунжера

Таким образом, вам не нужно добавлять CSS за пределы компонента. CSS как

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

работает изнутри компонента, а селектор применяется, только если класс someClassустановлен на элементе хоста.


Я должен был сделать someField = trueв ngOnInit()-методе вместо ngAfterViewInit(). Я не мог заставить это работать иначе.
— Джон

Сделал здесь развилку, которая показывает фактическую :hostчасть работы. Где я могу узнать больше о параметре хоста в декораторе @Component () (синтаксис для меня неочевиден, а документация @Component мало что объясняет ) или узнать больше о предпочитаемом HostBinding (он указан только как Интерфейс на Сайт Angular2?)
— Красный горох

Я не знаю лучших документов, но это просто другой способ делать то, что вы можете сделать@Input() @Output() @HostBinding() @HostListener() @ViewChild(ren)() @ContentChild(ren)()
— Гюнтер Цохбауэр

1
использовать привязку с другим именем для привязки хоста, которая возвращает инвертированное значение@HostBinding('class.xxx') get xxxclass(){ return !this.someField;}
— Günter Zöchbauer

1
@YochaiAkoka не уверен, что вы имеете в виду. Я не знаю об этом правиле. Меньше, как правило, больше, поэтому, если вы можете избежать добавления дополнительных элементов, вам следует избегать этого.
— Гюнтер Цохбауэр,

184

Ответ Гюнтера великолепен (вопрос требует атрибута динамического класса), но я подумал, что добавлю только для полноты ...

Если вы ищете быстрый и понятный способ добавить один или несколько статических классов к элементу 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>

1
Люблю это для простоты. Однако в моем случае элемент хоста инкапсулирован с другим атрибутом, давайте назовем его, ngcontent_hostчем любой из атрибутов элементов в моем шаблоне , let's call those ngcontent_template , so if I put a style in the styleUrls` моего компонента, они не будут влиять на элемент хоста, потому что они не будут влиять ngcontent_host, они может влиять только на элементы шаблона; они могут только влиять ngcontent_template. Я ошибаюсь? Есть предложения по этому поводу? Я думаю, что я всегда мог повернутьViewEncapsulation.None
— Красный горох

11
Другой способ - просто пропустить переменную @HostBinding('class.someClass') true;. Вы даже можете сделать это из любого класса, который расширяет ваш компонент.
— adamdport

3
Чтобы добавить несколько классов, вы можете сделать host: {'[class]': '"class1 class2"'}
— jbojcic

4
Если вы используете {}вариант host:, вы можете установить use-host-property-decoratorзначение falsein tslint.json. В противном случае вы получите предупреждения IDE. @adamdport Этот метод больше не работает. Используя Angular 5.2.2 в нашем приложении.
— Рууд Воост

1
Это только я, или старый способ кажется лучше, чем новый? Я уверен, что у них были веские причины для миграции, но,
— раздавить

13

Вы можете просто добавить @HostBinding('class') class = 'someClass';в свой класс @Component .

Пример:

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

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

  constructor() {}      

  ngOnInit() {}
}

1
Имя класса директива может также использоваться и лучше избегать использования в classкачестве имени переменной (так как вы можете ссылаться на него и изменить его позже). Пример: @HostBinding('className') myTheme = 'theme-dark';.
— CPHPython

3

Если вы хотите добавить динамический класс к вашему хост-элементу, вы можете объединить его HostBindingс геттером как

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

Демонстрация Stackblitz по адресу https://stackblitz.com/edit/angular-dynamic-hostbinding


0

Вот как я это сделал (Angular 7):

В компонент добавьте вход:

@Input() componentClass: string = '';

Затем в HTML-шаблон компонента добавьте что-то вроде:

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

И, наконец, в шаблоне HTML, где вы создаете экземпляр компонента:

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

Отказ от ответственности: я довольно новичок в Angular, так что, возможно, мне просто повезло здесь!


2
Немного некро, но: это не добавляет класс CSS к элементу хоста - который является элементом для <root>тега, а не чем-либо, что вы добавляете в шаблон элемента.
— миллимус
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.