K.Jarrad
K.Jarrad

Reputation: 33

what is the solution of erro that (Cannot read property 'innerHTML' of undefined ) in implementing google maps

when I were implementing in my ionic 3 project I have been included google maps in it after I set all the steps were necessary for use maps correctly in ionic 3

(page : google maps with searching in search bar)

my typescript code for mapping is :

import { Component, ElementRef, ViewChild, NgZone } from '@angular/core';
import { IonicPage, NavController, NavParams, Platform, ViewController } from 'ionic-angular';
import { Geolocation } from '@ionic-native/geolocation';
import { GoogleMapsProvider } from '../../providers/google-maps/google-maps';


declare var google ;
@IonicPage()
@Component({
  selector: 'page-map2',
  templateUrl: 'map2.html',
})
export class Map2Page {
    @ViewChild('map') mapElement: ElementRef;
    @ViewChild('pleaseConnect') pleaseConnect: ElementRef;

    latitude: number;
    longitude: number;
    autocompleteService: any;
    placesService: any;
    query: string = '';
    places: any = [];
    searchDisabled: boolean;
    saveDisabled: boolean;
    location: any; 

  constructor(public navCtrl: NavController, public zone: NgZone, public maps: GoogleMapsProvider, public platform: Platform, public geolocation: Geolocation, public viewCtrl: ViewController) {
    this.searchDisabled = true;
    this.saveDisabled = true;

  }

  ionViewDidLoad(): void {
    let mapLoaded = this.maps.init(this.mapElement.nativeElement, this.pleaseConnect.nativeElement).then(() => {

      this.autocompleteService = new google.maps.places.AutocompleteService();
      this.placesService = new google.maps.places.PlacesService(this.maps.map);
      this.searchDisabled = false;

  });
  }

  selectPlace(place){

    this.places = [];

    let location = {
        lat: null,
        lng: null,
        name: place.name
    };

    this.placesService.getDetails({placeId: place.place_id}, (details) => {

        this.zone.run(() => {

            location.name = details.name;
            location.lat = details.geometry.location.lat();
            location.lng = details.geometry.location.lng();
            this.saveDisabled = false;

            this.maps.map.setCenter({lat: location.lat, lng: location.lng});

            this.location = location;

        });

    });

}

searchPlace(){

    this.saveDisabled = true;

    if(this.query.length > 0 && !this.searchDisabled) {

        let config = {
            types: ['geocode'],
            input: this.query
        }

        this.autocompleteService.getPlacePredictions(config, (predictions, status) => {

            if(status == google.maps.places.PlacesServiceStatus.OK && predictions){

                this.places = [];

                predictions.forEach((prediction) => {
                    this.places.push(prediction);
                });
            }

        });

    } else {
        this.places = [];
    }

}

save(){
    this.viewCtrl.dismiss(this.location);
}

close(){
    this.viewCtrl.dismiss();
}  

}

and my html code for this page is :

<ion-header>
    <ion-navbar color="primary">
        <ion-buttons left>
            <button ion-button (click)="close()">Cancel</button>
        </ion-buttons>
        <ion-buttons right>
            <button [disabled]="saveDisabled" ion-button (click)="save()">Save</button>
        </ion-buttons>
    </ion-navbar>

    <ion-toolbar>
        <ion-searchbar [(ngModel)]="query" (ionInput)="searchPlace()"></ion-searchbar>
    </ion-toolbar>

    <ion-list>
        <ion-item *ngFor="let place of places" (touchstart)="selectPlace(place)">{{place.description}}</ion-item>
    </ion-list>

</ion-header>

<ion-content>

    <div #pleaseConnect id="please-connect">
        <p>Please connect to the Internet...</p>
    </div>

    <div #map id="map">
        <ion-spinner></ion-spinner>
    </div>

</ion-content>

my issue that when I go to test the code and view the results it give me an error which is :

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'innerHTML' of undefined
TypeError: Cannot read property 'innerHTML' of undefined
    at Object._.QA (util.js:19)
    at l$.attributionText_changed (places_impl.js:40)
    at Rc (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:50)
    at l$._.J.bindTo (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:118)
    at Object.m$.f (places_impl.js:40)
    at yw.<anonymous> (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:146)
    at Object._.Q (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:62)
    at new yw (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:146)
    at map2.ts:37
    at t.invoke (polyfills.js:3)
    at Object._.QA (util.js:19)
    at l$.attributionText_changed (places_impl.js:40)
    at Rc (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:50)
    at l$._.J.bindTo (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:118)
    at Object.m$.f (places_impl.js:40)
    at yw.<anonymous> (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:146)
    at Object._.Q (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:62)
    at new yw (js?key=AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U&libraries=places:146)
    at map2.ts:37
    at t.invoke (polyfills.js:3)
    at c (polyfills.js:3)
    at polyfills.js:3
    at t.invokeTask (polyfills.js:3)
    at Object.onInvokeTask (core.js:4620)
    at t.invokeTask (polyfills.js:3)
    at r.runTask (polyfills.js:3)
    at o (polyfills.js:3)
    at <anonymous>

the line 37 in ts code which look like its the reason of error is this line :

this.placesService = new google.maps.places.PlacesService(this.maps.map);

I have searched for this error but I can't find a solution , specially it occurs in a code for implementing google maps

the google map provider code is

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { ConnectivityServiceProvider } from '../connectivity-service/connectivity-service';
import { Geolocation } from '@ionic-native/geolocation';

declare var google ;
@Injectable()
export class GoogleMapsProvider {
  mapElement: any;
  pleaseConnect: any;
  map: any;
  mapInitialised: boolean = false;
  mapLoaded: any;
  mapLoadedObserver: any;
  currentMarker: any;
  apiKey: string = "AIzaSyCfydQz_KdwPVD98a8jMWG3DxB_H-EvJ8U";

  constructor(public http: HttpClient , public connectivityService: ConnectivityServiceProvider, public geolocation: Geolocation) {
    console.log('Hello GoogleMapsProvider Provider');
  }

  init(mapElement: any, pleaseConnect: any): Promise<any> {

    this.mapElement = mapElement;
    this.pleaseConnect = pleaseConnect;

    return this.loadGoogleMaps();

  }

  loadGoogleMaps(): Promise<any> {

    return new Promise((resolve) => {

      if(typeof google == "undefined" || typeof google.maps == "undefined"){

        console.log("Google maps JavaScript needs to be loaded.");
        this.disableMap();

        if(this.connectivityService.isOnline()){

          window['mapInit'] = () => {

            this.initMap().then(() => {
              resolve(true);
            });

            this.enableMap();
          }
          let script = document.createElement("script");
          script.id = "googleMaps";

          if(this.apiKey){
            script.src = 'http://maps.google.com/maps/api/js?key=' + this.apiKey + '&callback=mapInit&libraries=places';
          } else {
            script.src = 'http://maps.google.com/maps/api/js?callback=mapInit';      
          }

          document.body.appendChild(script); 

        }
      } else {

        if(this.connectivityService.isOnline()){
          this.initMap();
          this.enableMap();
        }
        else {
          this.disableMap();
        }

        resolve(true);

      }

      this.addConnectivityListeners();

    });

  }

  initMap(): Promise<any> {

    this.mapInitialised = true;

    return new Promise((resolve) => {

      this.geolocation.getCurrentPosition().then((position) => {

        let latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);

        let mapOptions = {
          center: latLng,
          zoom: 15,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        }

        this.map = new google.maps.Map(this.mapElement, mapOptions);
        resolve(true);

      });

    });

  }

  disableMap(): void {

    if(this.pleaseConnect){
      this.pleaseConnect.style.display = "block";
    }

  }

  enableMap(): void {

    if(this.pleaseConnect){
      this.pleaseConnect.style.display = "none";
    }

  }

  addConnectivityListeners(): void {

    this.connectivityService.watchOnline().subscribe(() => {

      setTimeout(() => {

        if(typeof google == "undefined" || typeof google.maps == "undefined"){
          this.loadGoogleMaps();
        }
        else {
          if(!this.mapInitialised){
            this.initMap();
          }

          this.enableMap();
        }

      }, 2000);

    });

    this.connectivityService.watchOffline().subscribe(() => {

      this.disableMap();

    });

  }

}

what is the solution of that error , please

and there is another question around the subject of google maps .. Is there a way to get the information about places from google maps and show it in the project on a special alert or toast or modal or something like that ? (the mean point it to get the data into the project from google maps)

Thanks at all

Upvotes: 0

Views: 1536

Answers (1)

Daniel W Strimpel
Daniel W Strimpel

Reputation: 8470

Your initMap method is an asynchronous function, however your code does not always treat it as such. For example, there is a portion of your loadGoogleMaps method with the following:

if (this.connectivityService.isOnline()) {
    this.initMap();
    this.enableMap();
}
else {
    this.disableMap();
}

resolve(true);

The problem here is that you are enabling the map and resolving the promise in this method too early (meaning before the work in initMap has completed). You need to make sure that you do this work after the map initialization has completed.

if (this.connectivityService.isOnline()) {
    this.initMap().then(() => {
        this.enableMap();
        resolve(true);
    });
}
else {
    this.disableMap();
    resolve(true);
}

Upvotes: 1

Related Questions