1

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.

1
  • Did you try debugging the writeValue(value: string) method with console.log()
    – Zanda
    Commented Apr 14 at 10:08

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.