Jak dodać „klasę” do elementu hosta?

190

Nie wiem, jak dodać do komponentu atrybut klasy<component></component> dynamicznej, ale wewnątrz szablonu html (component.html).

Jedynym rozwiązaniem, jakie znalazłem, jest modyfikacja elementu za pomocą rodzimego elementu „ElementRef”. To rozwiązanie wydaje się trochę skomplikowane, aby zrobić coś, co powinno być bardzo proste.

Innym problemem jest to, że CSS musi zostać zdefiniowany poza zakresem komponentu, co zrywa z enkapsulacją komponentu.

Czy istnieje prostsze rozwiązanie? Coś jak <root [class]="..."> .... </ root>w szablonie.

lascarayf
źródło

Odpowiedzi:

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

Przykład plunkera

W ten sposób nie musisz dodawać CSS poza komponentem. Jak CSS

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

działa od wewnątrz komponentu, a selektor jest stosowany tylko wtedy, gdy klasa someClassjest ustawiona na elemencie hosta.

Günter Zöchbauer
źródło
Musiałem zrobić to someField = truew ngOnInit()-method zamiast ngAfterViewInit(). W przeciwnym razie nie mogłem go uruchomić.
Jan
Zrobiłem tutaj widelec, który pokazuje rzeczywistą :hostdziałającą część. Gdzie mogę dowiedzieć się więcej o parametrze hosta w dekoratorze @Component () (składnia nie jest dla mnie oczywista, a dokumentacja @Component nie wyjaśnia zbyt wiele ) lub dowiedzieć się więcej o preferowanym HostBinding (jest wymieniony tylko jako interfejs na Witryna Angular2?)
The Red Pea
Nie znam lepszych dokumentów, ale to po prostu inny sposób robienia tego, co możesz zrobić@Input() @Output() @HostBinding() @HostListener() @ViewChild(ren)() @ContentChild(ren)()
Günter Zöchbauer
1
użyj gettera o innej nazwie dla powiązania hosta, które zwraca odwróconą wartość@HostBinding('class.xxx') get xxxclass(){ return !this.someField;}
Günter Zöchbauer
1
@YochaiAkoka nie jesteś pewien, o czym mówisz. Nie znam tej zasady. Mniej to zwykle więcej, więc jeśli możesz uniknąć dodawania dodatkowych elementów, powinieneś tego unikać.
Günter Zöchbauer
184

Odpowiedź Güntera jest świetna (pytanie dotyczy dynamicznego atrybutu klasy), ale pomyślałem, że dodam tylko dla kompletności ...

Jeśli szukasz szybkiego i czystego sposobu na dodanie jednej lub więcej klas statycznych do elementu hosta komponentu (tj. Do celów stylizacji motywu), możesz po prostu:

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

A jeśli użyjesz klasy w tagu wejściowym, Angular scali klasy, tj.

<my-component class="someClass2">
  I have both someClass1 & someClass2 applied to me
</my-component>
JoshuaDavid
źródło
1
Uwielbiam to za prostotę. Jednak w moim przypadku element hosta jest enkapsulowany innym atrybutem, nazwijmy go ngcontent_hostniż którykolwiek z atrybutów elementów w moim szablonie , let's call those ngcontent_template , so if I put a style in the styleUrls` mojego komponentu, nie wpłyną one na element hosta, ponieważ nie wpłyną ngcontent_host, one może wpływać tylko na elementy szablonu; mogą tylko wpływać ngcontent_template. Czy się mylę? Wszelkie sugestie na ten temat? ViewEncapsulation.None
Wydaje
11
Innym sposobem jest po prostu pominąć zmienną @HostBinding('class.someClass') true;. Możesz to zrobić nawet z dowolnej klasy, którą rozszerza twój komponent.
adamdport,
3
Aby dodać wiele klas, możesz zrobić host: {'[class]': '"class1 class2"'}
jbojcic
4
Jeśli korzystasz z {}wariantu host :, możesz chcieć ustawić use-host-property-decoratorustawienie na falsein tslint.json. W przeciwnym razie otrzymasz ostrzeżenia IDE. @adamdport Ta metoda nie działa (już). Korzystanie z Angulara 5.2.2 w naszej aplikacji.
Ruud Voost
1
Czy to tylko ja, czy może stary sposób wydaje się lepszy niż nowy? Jestem pewien, że mieli dobry powód do migracji, ale ja ...
zmiażdżyć
13

Możesz po prostu dodać @HostBinding('class') class = 'someClass';do swojej klasy @Component .

Przykład:

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

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

  constructor() {}      

  ngOnInit() {}
}
Mike D3ViD Tyson
źródło
1
ClassName dyrektywa może być również używany i lepiej jest unikać używania classjako nazwa zmiennej (ponieważ można go odwołać i zmienić go później). Przykład: @HostBinding('className') myTheme = 'theme-dark';.
CPHPython
0

Oto jak to zrobiłem (Angular 7):

W komponencie dodaj dane wejściowe:

@Input() componentClass: string = '';

Następnie w szablonie HTML komponentu dodaj coś takiego:

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

I wreszcie w szablonie HTML, w którym komponent występuje:

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

Oświadczenie: Jestem dość nowy w Angular, więc mogę mieć szczęście!

zippycoder
źródło
2
Nieco nekro, ale: to nie dodaje klasy CSS do elementu hosta - który jest elementem dla <root>tagu, a nie niczego, co dodajesz do szablonu elementu.
millimoose