Last active
October 27, 2023 16:00
-
-
Save cyrillbrito/f387212029bcc97287088297492c54d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Directive({ | |
standalone: true, | |
providers: [ | |
{ | |
provide: NG_VALUE_ACCESSOR, | |
multi: true, | |
useExisting: HostControlDirective, | |
}, | |
], | |
}) | |
export class HostControlDirective implements ControlValueAccessor { | |
control!: FormControl; | |
private injector = inject(Injector); | |
private subscription?: Subscription; | |
ngOnInit(): void { | |
const ngControl = this.injector.get(NgControl, null, { self: true, optional: true }); | |
if (ngControl instanceof FormControlName) { | |
const group = this.injector.get(ControlContainer).control as UntypedFormGroup; | |
this.control = group.controls[ngControl.name!] as FormControl; | |
return; | |
} | |
if (ngControl instanceof FormControlDirective) { | |
this.control = ngControl.control; | |
return; | |
} | |
if (ngControl instanceof NgModel) { | |
this.subscription = ngControl.control.valueChanges.subscribe(newValue => { | |
// The viewToModelUpdate updates the directive and triggers the ngModelChange. | |
// So we want to called it when the value changes except when it comes from the parent (ngModel input). | |
// The `if` checks if the newValue is different from the value on the ngModel input or from the current value. | |
if (ngControl.model !== newValue || ngControl.viewModel !== newValue) { | |
ngControl.viewToModelUpdate(newValue); | |
} | |
}); | |
this.control = ngControl.control; | |
return; | |
} | |
// Fallback | |
this.control = new FormControl(); | |
} | |
writeValue(): void { } | |
registerOnChange(): void { } | |
registerOnTouched(): void { } | |
ngOnDestroy(): void { | |
this.subscription?.unsubscribe(); | |
} | |
} | |
// Usage example | |
@Component({ | |
selector: 'app-custom-input', | |
template: `<input [formControl]="hcd.control" />`, | |
standalone: true, | |
imports: [ReactiveFormsModule], | |
hostDirectives: [HostControlDirective], | |
}) | |
export class CustomInputComponent { | |
hcd = inject(HostControlDirective); | |
} |
@pookdeveloper Fixed the depredated flags, thanks. Maybe use are using NoopValueAccessorDirective
together with my HostControlDirective
and since both provide NG_VALUE_ACCESSOR
it is causing problems. With my solution you don't need the NoopValueAccessorDirective
since it is already incorporated
@cyrillbrito your HostControlDirective is my NoopValueAccessorDirective i only use this name , but i hace the same code
The problem is that I have move the code in NgOninit to constructor.
I had some problems with array values, the code above caused the changes to be triggered twice, so I changed the condition to this:
this.subscription = ngControl.control.valueChanges.subscribe(newValue => {
// The viewToModelUpdate updates the directive and triggers the ngModelChange.
// So we want to called it when the value changes except when it comes from the parent (ngModel input).
// The `if` checks if the newValue is different from the value on the ngModel input or from the current value.
if (ngControl.model !== newValue && ngControl.viewModel !== newValue) {
ngControl.viewToModelUpdate(newValue);
}
});
So that only when both models are different it triggers the update. Now it seems to work
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@cyrillbrito I get and error with your example:
![image](https://user-images.githubusercontent.com/3384734/235086939-b7061f99-cecd-43c4-a907-efc5fe28a014.png)