Hello everyone! I'm trying to update an element class value in a directive. This is my code:
@Directive({
selector: 'button[appButton], a[appButton]',
standalone: true,
})
export class ButtonDirective implements OnInit, OnChanges {
@Input() props: VariantProps<typeof buttonVariants> = {};
@Input() className: string | undefined;
// buttonVariants() returns TailwindCSS classes
elementClass = signal(buttonVariants());
constructor(private elementRef: ElementRef<HTMLElement>) {}
ngOnInit(): void {
this.elementRef.nativeElement.className = this.elementClass();
}
ngOnChanges(): void {
this.elementClass.set(
buttonVariants({ ...this.props, className: this.className })
);
this.elementRef.nativeElement.className = this.elementClass();
}
}
Here, the function buttonVariants() returns a string with a bunch of Tailwind classes.
There are a few things that are bugging me:
-
If I remove the
ngOnInitmethod, the elements that uses this directive without props don't get the classes. I thoughtngOnChangesmethod runs everytime there are inputs and they change, even when they have a default value. Is this not the case? -
If I remove the signal and equal the element class directly to
buttonVariants()fn and update the value inngOnChanges, the component don't update their view when changing the value of the inputs. Why is a signal necessary here?
This directive is inspired by @shadcn/ui. Even if it works like this, I'm trying to improve the code. Anyone got any ideas?
Here is a stackblitz demo: https://stackblitz.com/edit/obyfkw-h59ftc?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fbutton%2Fvariants.ts,src%2Fapp%2Fbutton%2Fbutton.directive.ts