@@ -95,6 +95,8 @@ export function ɵɵcontrol<T>(value: T, sanitizer?: SanitizerFn | null): void {
9595
9696 const control = getControlDirective ( tNode , lView ) ;
9797 if ( control ) {
98+ updateControlClasses ( lView , tNode , control ) ;
99+
98100 if ( tNode . flags & TNodeFlags . isFormValueControl ) {
99101 updateCustomControl ( tNode , lView , control , 'value' ) ;
100102 } else if ( tNode . flags & TNodeFlags . isFormCheckboxControl ) {
@@ -449,6 +451,34 @@ function isRelevantSelectMutation(mutation: MutationRecord) {
449451 return false ;
450452}
451453
454+ /**
455+ * Updates the configured classes for the control.
456+ *
457+ * @param lView The `LView` that contains the control.
458+ * @param tNode The `TNode` of the control.
459+ * @param control The `ɵControl` directive instance.
460+ */
461+ function updateControlClasses ( lView : LView , tNode : TNode , control : ɵControl < unknown > ) {
462+ if ( control . classes ) {
463+ const bindings = getControlBindings ( lView ) ;
464+ bindings . classes ??= { } ;
465+ const state = control . state ( ) ;
466+ const renderer = lView [ RENDERER ] ;
467+ const element = getNativeByTNode ( tNode , lView ) as HTMLElement ;
468+
469+ for ( const [ className , enabled ] of control . classes ) {
470+ const isEnabled = enabled ( ) ;
471+ if ( controlClassBindingUpdated ( bindings . classes , className , isEnabled ) ) {
472+ if ( isEnabled ) {
473+ renderer . addClass ( element , className ) ;
474+ } else {
475+ renderer . removeClass ( element , className ) ;
476+ }
477+ }
478+ }
479+ }
480+ }
481+
452482/**
453483 * Updates the inputs of a custom form control component with the latest state from the `field`.
454484 *
@@ -839,6 +869,8 @@ type ControlBindingKeys = Exclude<
839869 */
840870type ControlBindings = {
841871 [ K in ControlBindingKeys ] ?: unknown ;
872+ } & {
873+ classes : { [ className : string ] : boolean } ;
842874} ;
843875
844876/**
@@ -893,7 +925,7 @@ function getControlBindings(lView: LView): ControlBindings {
893925 */
894926function controlBindingUpdated (
895927 bindings : ControlBindings ,
896- key : ControlBindingKeys ,
928+ key : Exclude < ControlBindingKeys , 'classes' > ,
897929 value : unknown ,
898930) : boolean {
899931 const oldValue = bindings [ key ] ;
@@ -904,6 +936,27 @@ function controlBindingUpdated(
904936 return true ;
905937}
906938
939+ /**
940+ * Updates a control class binding if changed, then returns whether it was updated.
941+ *
942+ * @param bindings The control class bindings to check.
943+ * @param className The class name to check.
944+ * @param value The new value to check against.
945+ * @returns `true` if the class binding has changed.
946+ */
947+ function controlClassBindingUpdated (
948+ bindings : { [ className : string ] : boolean } ,
949+ className : string ,
950+ value : boolean ,
951+ ) : boolean {
952+ const oldValue = bindings [ className ] ;
953+ if ( Object . is ( oldValue , value ) ) {
954+ return false ;
955+ }
956+ bindings [ className ] = value ;
957+ return true ;
958+ }
959+
907960/**
908961 * Sets a boolean attribute on an element.
909962 *
0 commit comments