I have this code which sets a class on the host:
@HostBinding('class.fixed') true;
What I would like to do is make this a variable class that I can modify. How can I do this?
I have this code which sets a class on the host:
@HostBinding('class.fixed') true;
What I would like to do is make this a variable class that I can modify. How can I do this?
This can't be made variable.
What you can do instead is to bind to the class property directly
@HostBinding('class') classes = 'class1 class2 class3';
[class]="..."
that might hit this approach as well. –
Parsonage @HostBind('class') hostClasses: string;
initially then in ngOnInit
(and optionally in ngOnChanges
for more dynamism): this.hostClasses = this.getHostClasses();
and have whatever logic you'd want in the getHostClasses
method, possibly pulling from some other @Input()
values. –
Scholl host object
appends classes, but HostBinding
replaces all other classes –
Erythroblastosis @HostBinding('class.your-class')
- https://mcmap.net/q/121937/-how-to-add-remove-class-from-directive –
Extend @HostBinding
definitions. However, multiple @HostBinding('class')
in the component are still conflicting. –
Pageantry If you have a limited number of classes you can conditionally add each one:
@HostBinding('class.c1') get c1 () { return this.useC1; }
@HostBinding('class.c2') get c2 () { return this.useC2; }
Note that .c1
and .c2
need to be defined outside the component.
()
for it to work (e.g. get c1() { return this.useC1; }
. –
Corral .c1
and .c2
outside of the component if you use the :host
selector. See this answer for an example: #35169183 –
Holily I have to contradict the other answers, there is no reason why binding class.foo
shouldn't work. Actually, the following format works properly:
@HostBinding('class.foo') variableName = true;
A common gotcha that foils many developers is the scope of the CSS class. You might need to change the selector scope in order to make the class visible to the selector itself, and not its children (you can see a discussion here).
To make the class visible to the Angular component itself you have two choices: you can either change the View Encapsulation to None
(it will alter the behavior), or you can match the class with the :host
pseudoselector.
In other words, the problem is that HostBinding
only sees the host scope, it means that it only sees the classes and the id applied to the component itself, not to its children. So when you write your CSS, you need to specify that CSS belongs to the component itself (the host pseudoelement).
According to Angular documentation:
Use the :host pseudo-class selector to target styles in the element that hosts the component (as opposed to targeting elements inside the component's template).
You can easily specify the host scope just adding :host
before your CSS rule:
:host.foo { // It only matches <component-name class="foo">
/* Your CSS here */
}
In place of
.foo { // It matches any <element class="foo" /> inside <component-name>
/* Your CSS here */
}
If you want, I created a working Plunker that you can see clicking here
(.className)
when chaining it off :host
. I think you make chain just like any other selector string. :host.className
–
Holily Günter's answer isn't really helpful in case of already having some class names bound to a variable.
A good way to combine variable string class names with boolean style predefined class names is to use the classnames npm package.
Use it together with the @HostBinding
and a setter function to get amazing results:
import * as classNames from 'classnames';
(...)
@HostBinding('class') get classes(): string {
return classNames(this.getDynamicClassName(), {
'is-open': this.isOpen,
'has-children': this.hasChildren
});
}
@Input()
class = '';
@HostBinding('attr.class')
get btnClasses() {
return [
'btn',
this.someClassAsString,
this.enableLight ? 'btn-secondary-light' : '',
this.class,
].filter(Boolean).join(' ');
};
You can hijack the class attribute with an input and add what you need to it in a hostbinding
You can create some separated directives with class.
For example: I have a button in my page, and has may states: default
, primary
, danger
and fluid
. Button can have many different states, but I'll show you with theese three states because of huge amount of code. So let's get start it!
button.ts
//default button
@Directive({
selector: '[appButtonDefault]'
})
export class ButtonDefaultDirective {
// the name of the field is not important
// if you put this directive to element,
// this element will have the class called 'button--default'
@HostBinding("class.button--default")
private defaultClass: boolean = true;
}
//primary button
@Directive({
selector: '[appButtonPrimary]'
})
export class ButtonPrimaryDirective {
// the name of the field is not important
// if you put this directive to element,
// this element will have the class called 'button--primary'
@HostBinding("class.button--primary")
private primaryClass: boolean = true;
}
// danger button
@Directive({
selector: '[appButtonDanger]'
})
export class ButtonDangerDirective {
// the name of the field is not important
// if you put this directive to element,
// this element will have the class called 'button--primary'
@HostBinding("class.button--danger")
private dangerClass: boolean = true;
}
@Directive({
selector: '[appButtonFluid]'
})
export class ButtonFluidDirective {
// the name of the field is not important
// if you put this directive to element,
// this element will have the class called 'button--primary'
@HostBinding("class.button--fluid")
private fluidClass: boolean = true;
}
// you need to also create a component class,
// that import styles for this button
@Component({
//just put created selectors in your directives
selector: `[appButtonDefault], [appButtonPrimary],
[appButtonDanger], [appButtonFluid]`,
styleUrls: ['<-- enter link to your button styles -->'],
// it is required, because the content of <button> tag will disappear
template: "<ng-content></ng-content>"
})
export class ButtonComponent {}
// you don't have to do it, but I prefet to do it
@NgModule({
declarations: [
ButtonDefaultDirective,
ButtonPrimaryDirective,
ButtonDangerDirective,
ButtonFluidDirective,
ButtonComponent
],
exports: [
ButtonDefaultDirective,
ButtonPrimaryDirective,
ButtonDangerDirective,
ButtonFluidDirective,
ButtonComponent
]
})
export class ButtonModule {}
Don't forget to import ButtonModule
to your app.module.ts
file. It is very important.
app.component.html
<!-- This button will have the class 'button--default' -->
<button appButtonDefault>Default button</button>
<!-- But this button will have the class 'button--primary button--fluid' -->
<button appButtonPrimary appButtonFluid>Primary and fluid</button>
I hope it helps.
There are lots of answers already, but none have mentioned NgClass
.
In my opinion, the most reliable and consistent way to do this is extending NgClass
because it provides everything we need out-of-the-box-ish:
@Directive({ selector: '[myDirective]'})
export class MyDirective extends NgClass {
constructor(
_iterableDiffers: IterableDiffers,
_keyValueDiffers: KeyValueDiffers,
_ngEl: ElementRef,
_renderer: Renderer2
) {
super(_iterableDiffers, _keyValueDiffers, _ngEl, _renderer);
}
setClass() {
this.ngClass = {
underline: true,
bold: true,
italic: true,
pretty: false
};
// or
this.ngClass = ['asd', 'abc', 'def'];
// or
this.ngClass = 'foo';
}
}
Easiest way would be like this
@Directive({
selector: '[appSomeDirective]',
host: {
class: 'some-directive-classname another-classname',
},
})
export class SomeDirective {}
© 2022 - 2024 — McMap. All rights reserved.