I'm implementing a standalone component in Angular that wraps the gmpx-place-autocomplete
web component from Google Maps Platform and implements the ControlValueAccessor interface to use it within a reactive form.
When I try to use the component in my form, I receive the following error:
ERROR TypeError: Cannot read properties of null (reading 'writeValue')
at Yo (forms.mjs:3236:21)
at e.addControl (forms.mjs:5173:7)
at e._setUpControl (forms.mjs:5751:41)
at e.ngOnChanges (forms.mjs:5698:30)
at e.Y0 (core.mjs:3136:10)
at qp (core.mjs:4199:10)
at bb (core.mjs:4226:5)
at Im (core.mjs:4183:9)
at js (core.mjs:4138:5)
at mv (core.mjs:12111:9)
My Current Implementation
Google Place Autocomplete Component (standalone):
TS
import { Component, ElementRef, forwardRef, OnInit, ViewChild, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { GoogleMapsLoaderService } from 'src/app/_services/google-maps-loader.service';
@Component({
selector: 'app-google-place-autocomplete',
templateUrl: './google-place-autocomplete.component.html',
styleUrls: ['./google-place-autocomplete.component.scss'],
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule
],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GooglePlaceAutocompleteComponent),
multi: true,
}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GooglePlaceAutocompleteComponent implements ControlValueAccessor, OnInit {
@ViewChild('autocomplete', { static: false }) autocompleteRef!: ElementRef;
value: string = '';
disabled = false;
onChange = (value: any) => { };
onTouched = () => { };
constructor(private googleMapsLoader: GoogleMapsLoaderService) { }
async ngOnInit() {
await this.googleMapsLoader.load();
}
writeValue(value: string): void {
this.value = value;
this.updateComponentValue();
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.autocompleteRef?.nativeElement) {
this.autocompleteRef.nativeElement.disabled = isDisabled;
}
}
onPlaceSelected(event: any) {
const place = event.detail?.place;
this.value = place?.formattedAddress || '';
this.onChange(this.value);
this.onTouched();
}
private updateComponentValue(): void {
if (this.autocompleteRef?.nativeElement) {
if (typeof this.autocompleteRef.nativeElement.setValue === 'function') {
this.autocompleteRef.nativeElement.setValue(this.value);
} else {
this.autocompleteRef.nativeElement.value = this.value;
}
}
}
}
HTML
<gmpx-place-autocomplete
#autocomplete
style="width: 100%"
[value]="value"
(gmpx-placechange)="onPlaceSelected($event)">
</gmpx-place-autocomplete>
Usage in Form Component:
@Component({
selector: 'app-location-form',
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule,
GooglePlaceAutocompleteComponent
],
template: `
<form [formGroup]="locationForm" (ngSubmit)="onSubmit()">
<app-google-place-autocomplete formControlName="address"></app-google-place-autocomplete>
<button type="submit">Save</button>
</form>
`
})
export class LocationFormComponent implements OnInit {
locationForm = this.fb.group({
address: ['', Validators.required]
});
constructor(private fb: FormBuilder) {}
ngOnInit(): void {}
onSubmit(): void {
if (this.locationForm.valid) {
console.log(this.locationForm.value);
}
}
}
Question: Why am I receiving this error and how can I fix it? Is there any known issue with standalone components implementing ControlValueAccessor? Any help would be greatly appreciated.
writeValue(value: string)
method withconsole.log()