我使用带有Angular 4的AGM库来开发组件。
该组件有4个输入:


1º输入:如果变量“ useGoogleMap”为false,则显示此输入,以便用户无需使用Google地图即可输入地址。
2º输入:当变量“ useGoogleMap”为true时,将显示AGM自动完成输入。
3º和4º输入:显示可编辑的经纬度输入,可在AGM地图上搜索。


问题是,如果我使用* ngIf =“ useGoogleMap”(和useGoogleMap = false),则AGM不会初始化,而当它使用useGoogleMap = true时,其未定义的地图可以使用(ngOnInit,ngOnChanges等)。

我也尝试过隐藏,但是隐藏或显示它不是自动的,只能在组件的某些输入的blur()下工作(不知道为什么)。

这是一些代码:



export class InputGooglePlacesComponent implements OnInit, OnChanges {
  @ViewChild('googlePlaceInput') googlePlaceInputElementRef: ElementRef;
  @ViewChild('map') map: AgmMap;
  @ViewChild('marker') marker: AgmMarker;
  @ViewChild('useGoogle') useGoogle: ElementRef;
  @ViewChild('manualAddress') manualAddress: ElementRef;

  @Input() public label: string;
  @Input() public field: string;
  @Input() public placeholder = 'Escribe una dirección';
  @Input() public form: FormGroup;

  @Output() selectedPlace = new EventEmitter();

  @Input() public latitud: number = AppSettings.GMAPS_LOCATION_DEFAULT.lat;
  @Input() public longitud: number = AppSettings.GMAPS_LOCATION_DEFAULT.lng;
  @Input() public direccion: string = null;

  public finishChanges = new EventEmitter();
  private formatted_address: string;
  public zoom = 12;
  public autocomplete: any = null;
  public useGoogleMap = false;

  constructor(private mapsAPILoader: MapsAPILoader, private ngZone: NgZone) {}

  ngOnInit() {
    if (this.useGoogleMap) {
      this.loadPlaces();
    }
  }

  httpGet() {
    const url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + this.direccion.replace(/ /g, '+') + '&key=' + AppSettings.GMAPS_API_KEY;
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", url, false ); // false for synchronous request
    xmlHttp.send( null );
    return xmlHttp.response;
  }


  ngOnChanges(changeRecord: SimpleChanges) {
    if (this.useGoogleMap) {
    if (!this.latitud || !this.longitud) {
      if (this.direccion && this.direccion !== '') {
        //No viene la latitud o longitud, y la dirección viene por BD. Se setea como dirección manual.
        this.manualAddress.nativeElement.value = this.direccion;
        this.useGoogleMapAPI(false);
      } else {
        //No viene ninguno de los 3 campos (lat, lng, dirección). Se setea direccion gmap por defecto.
        this.latitud = AppSettings.GMAPS_LOCATION_DEFAULT.lat;
        this.longitud = AppSettings.GMAPS_LOCATION_DEFAULT.lng;
        this.zoom = 9;

        this.mapsAPILoader.load().then(() => {

          let latlng;
          latlng = new google.maps.LatLng(this.latitud, this.longitud);

          new google.maps.Geocoder().geocode({ location: latlng }, (results, status) => {
            if (status === google.maps.GeocoderStatus.OK) {
              if (results[0]) {
                this.formatted_address = results[0].formatted_address;
              }

              this.selectedPlace.emit({
                formatted_address: this.formatted_address,
                latitud: this.latitud,
                longitud: this.longitud,
                coordinates: `POINT(${this.longitud} ${this.latitud})`
              });
            }
          });

          this.useGoogleMapAPI(true);
          this.map.triggerResize();
        });

      }
    } else {
      if (this.direccion && this.direccion !== '') {
        this.mapsAPILoader.load().then(() => {
          const location = JSON.parse(this.httpGet()).results[0];

          const latitud = Math.round(Math.abs(this.latitud) * 1000000) / 1000000;
          const geolatitud = Math.round(Math.abs(location.geometry.location.lat) * 1000000) / 1000000;

          const longitud = Math.round(Math.abs(this.longitud) * 1000000) / 1000000;
          const geolongitud = Math.round(Math.abs(location.geometry.location.lng) * 1000000) / 1000000;

          if ( Math.abs(latitud - geolatitud) <= 0.001 && Math.abs(longitud - geolongitud) <= 0.001) {
            //Coincide la dirección con la georeferencia
            this.initMarkerObservable({ coords: { lat: this.latitud, lng: this.longitud } }).subscribe(() => {
              this.finishChanges.emit();
            });
            this.zoom = 12;
            this.useGoogleMapAPI(true);
            this.map.triggerResize();
          } else {
            //No coincide la dirección con la georeferencia

            // this.latitud = null;
            // this.longitud = null;

            this.manualAddress.nativeElement.value = this.direccion;
            this.manualAddress.nativeElement.blur();
            this.useGoogleMapAPI(false);
          }
        });
      } else {
        this.latitud = AppSettings.GMAPS_LOCATION_DEFAULT.lat;
        this.longitud = AppSettings.GMAPS_LOCATION_DEFAULT.lng;
        this.zoom = 9;

        this.mapsAPILoader.load().then(() => {

          let latlng;
          latlng = new google.maps.LatLng(this.latitud, this.longitud);

          new google.maps.Geocoder().geocode({ location: latlng }, (results, status) => {
            if (status === google.maps.GeocoderStatus.OK) {
              if (results[0]) {
                this.formatted_address = results[0].formatted_address;
              }

              this.selectedPlace.emit({
                formatted_address: this.formatted_address,
                latitud: this.latitud,
                longitud: this.longitud,
                coordinates: `POINT(${this.longitud} ${this.latitud})`
              });
            }
          });

          this.useGoogleMapAPI(true);
          this.map.triggerResize();
        });
      }
    }
  }
  }

  loadPlaces() {
    this.mapsAPILoader.load().then(() => {
      this. autocomplete = new google.maps.places.Autocomplete(this.googlePlaceInputElementRef.nativeElement, {
        types: ['address']
      });

      this.autocomplete.addListener('place_changed', () => {
        this.ngZone.run(() => {
          const place: google.maps.places.PlaceResult = this.autocomplete.getPlace();
          if (place.geometry === undefined || place.geometry === null) {
            return;
          }
          this.latitud = place.geometry.location.lat();
          this.longitud = place.geometry.location.lng();

          this.selectedPlace.emit({
            formatted_address: place.formatted_address,
            latitud: place.geometry.location.lat(),
            longitud: place.geometry.location.lng(),
            coordinates: `POINT(${place.geometry.location.lng()} ${place.geometry.location.lat()})`
          });
        });
      });
    });
  }

  clickMarker(event: any) {
    if (this.useGoogleMap) {
    this.latitud = event.coords.lat;
    this.longitud = event.coords.lng;

    let latlng;
    latlng = new google.maps.LatLng(this.latitud, this.longitud);

    new google.maps.Geocoder().geocode({ location: latlng }, (results, status) => {
      if (status === google.maps.GeocoderStatus.OK) {
        if (results[0]) {
          this.formatted_address = results[0].formatted_address;
        }

        this.selectedPlace.emit({
          formatted_address: this.formatted_address,
          latitud: this.latitud,
          longitud: this.longitud,
          coordinates: `POINT(${this.longitud} ${this.latitud})`
        });
      }
    });
  }
  }

  initMarkerObservable(event: any): Observable<any> {
    if (this.useGoogleMap) {
      return new Observable<any>(observer => {
        this.latitud = event.coords.lat;
        this.longitud = event.coords.lng;

        let latlng;
        latlng = new google.maps.LatLng(this.latitud, this.longitud);

        const promise = new Promise((resolve, reject) => {
          new google.maps.Geocoder().geocode({ location: latlng }, (results, status) => {
            if (status === google.maps.GeocoderStatus.OK) {
              if (results[0]) {
                this.formatted_address = results[0].formatted_address;
              }

              this.selectedPlace.emit({
                formatted_address: this.formatted_address,
                latitud: this.latitud,
                longitud: this.longitud,
                coordinates: `POINT(${this.longitud} ${this.latitud})`
              });

              resolve();
            }
          });
        }).then(() => {
          observer.next('');
          observer.complete();
        });
      });
    }
  }

  triggerResize() {
    if (this.useGoogleMap) {
      this.map.triggerResize();
    }
  }

  resetPlaces() {
    if (this.useGoogleMap) {
      this.googlePlaceInputElementRef.nativeElement.value = '';
    }
  }


  setUseGoogle() {
    this.useGoogleMap = this.useGoogle.nativeElement.checked;
    if (this.useGoogleMap) {
      this.loadPlaces();
      this.map.triggerResize();
    }
  }

  useGoogleMapAPI(checked: boolean) {
    this.useGoogle.nativeElement.checked = checked;
    this.setUseGoogle();
  }

  recalculatePosition(event: any) {
    if (this.useGoogleMap) {
      if (event.srcElement.id === 'mapLatitud') {
        this.latitud = Number(event.srcElement.value);
      } else if (event.srcElement.id === 'mapLongitud') {
        this.longitud = Number(event.srcElement.value);
      }
      this.clickMarker({ coords: { lat: this.latitud, lng: this.longitud } });
    }
  }
}

agm-map {
    height: 300px;
}
.coords__input {
    margin: 10px 0;
}

<div class="form-group" [formGroup]="form">
    <div class="row">
        <div class="col-md-6"><label [for]="field">{{ label }}</label></div>
        <div class="col-md-6"><label for="useGoogle" ><input id="useGoogle" type="checkbox" (change)="setUseGoogle()" #useGoogle/>&nbsp;Usar google maps</label></div>
    </div>

    <div *ngIf="!useGoogleMap">
      <input [type]="text" class="form-control form-control-sm"
             [id]="field" [placeholder]="placeholder"
             [autocapitalize]="autocapitalize" [spellcheck]="spellcheck" #manualAddress>
    </div>

    <div *ngIf="useGoogleMap">
      <input
          [id]="field" [placeholder]="placeholder" [formControlName]="field"
          type="text"
          class="form-control form-control-sm"
          #googlePlaceInput />
      <div class="row">
        <div class="col-md-6">
          <input id="mapLatitud" type="number" class="form-control form-control-sm coords__input" [value]="latitud" (blur)="recalculatePosition($event)"/>
        </div>
        <div class="col-md-6">
          <input id="mapLongitud" type="number" class="form-control form-control-sm coords__input" [value]="longitud" (blur)="recalculatePosition($event)"/>
        </div>
      </div>
      <agm-map
          [usePanning]="true"
          [latitude]="latitud"
          [longitude]="longitud"
          [zoom]="zoom"
          (mapClick)=clickMarker($event) #map>
          <agm-marker [latitude]="latitud" [longitude]="longitud" #marker>
          </agm-marker>
      </agm-map>
      <app-form-control-errors [form]="form" [field]="field" [singleInput]="googlePlaceInput">
      </app-form-control-errors>

    </div>
</div>





我希望有人能帮助我。
我将更新任何进度。

最佳答案

一些解释:


如果在组件使用期内“ useGoogleMap”输入未更改,则可以访问ngAfterViewInit中的HTML(@ViewChild)。
如果您的值在组件生命周期中发生变化(因此可以多次调用ngOnChange),请使用setTimeout(()=> {...},0);围绕您的视图操作。在执行此操作之前,它将等待其他所有操作完成。


有关标题的更多信息:隐藏与所有浏览器都不兼容,因此在动态类中建议使用样式为“ display:none”的* ngIf或[ngClass]。

09-29 23:05