I tried following the steps laid out in this thread. It works to load searchboxes with this component:
map.component.html
<input id= 'box2' *ngIf="boxReady" class="controls" type="text" placeholder="Search Box">
<input id = 'box' class="controls" type="text" placeholder="Search Box">
map.component.ts
import {Component, Input, OnInit} from '@angular/core';
import {GoogleAPIService} from '../google-api.service';
declare var google: any;
@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss'],
})
export class MapComponent implements OnInit {
@Input() boxIdVar: string;
// @Input() id: string;
boxReady = false;
constructor(private _google: GoogleAPIService){}
ngOnInit(): void {
if (typeof google !== 'undefined') {
console.log(google);
console.log('Map.NgInit');
console.log(this.boxIdVar);
this.boxReady = true;
let input = document.getElementById('box');
let originSearch = new google.maps.places.SearchBox(input);
input = document.getElementById('box2');
let dest = new google.maps.places.SearchBox(input);
}
else {
console.log('Google was undefined Map');
}
}
}
However, if I add an *NgIf statement that will load one of the boxes only when the component is loaded then that searchbox no longer will work and I get an uncaught promise exception.
map.component.html
<input id= 'box2' *ngIf="boxReady" class="controls" type="text" placeholder="Search Box">
<input id = 'box' class="controls" type="text" placeholder="Search Box">
error found in the console:
ERROR Error: "Uncaught (in promise): TypeError: b is null
v$.prototype.o@https://maps.googleapis.com/maps-api-v3/api/js/40/5/places_impl.js:78:66
This all arose because I wanted to dynamically change the Id of the input box. But it seams that whenever an HTML element has some angular bound variable the functionality breaks.
You are querying the DOM in ngOnInit()
. This is too early in the component lifecycle for Angular to have added it to the DOM. Setting the *ngIf
condition to true doesn't immediately add it to the DOM.
Instead, you should run any code that requires the DOM element later in the component lifecycle, in ngAfterViewInit()
.
Also, a more "Angular" way to get a DOM element is to use @ViewChild()
.
<input *ngIf="boxReady" #box2 />
@ViewChild('box2') box2: ElementRef;
boxReady = false;
ngOnInit(): void {
this.boxReady = true;
const viewChild = this.box2 ? this.box2.nativeElement : null;
console.log('ngOnInit viewChild', viewChild); // null
}
ngAfterViewInit() {
const viewChild = this.box2.nativeElement;
console.log('ngAfterViewInit viewChild', viewChild);
}