【问题标题】:how to set debounce time to call for autocomplete google map api call from angular6如何设置去抖动时间以从 angular6 调用自动完成谷歌地图 api 调用
【发布时间】:2019-02-11 11:02:08
【问题描述】:

我已经制定了一个自定义指令来使用 google api 自动完成功能并尝试减少对 google 的 api 调用次数 这是我的代码。

请建议我设置一些延迟,以减少对谷歌服务器的 api 调用以实现输入自动完成功能

这个代码调用每个字母输入的 api 我想在 4 到 5 秒后或在输入一个单词后进行

//Google-place-directive.ts

import {
  Directive,
  ElementRef,
  OnInit,
  Output,
  EventEmitter
} from "@angular/core";

declare var google: any;

@Directive({
  selector: "[google-place]"
})
export class GooglePlacesDirective implements OnInit {
  @Output() onSelect: EventEmitter<any> = new EventEmitter();
  private element: HTMLInputElement;

  constructor(elRef: ElementRef) {
    //elRef will get a reference to the element where
    //the directive is placed
    this.element = elRef.nativeElement;
  }

  getFormattedAddress(place) {
    //@params: place - Google Autocomplete place object
    //@returns: location_obj - An address object in human readable format
    let location_obj = {};
    console.log(place);
    console.log(place.geometry.location.lat());
    console.log(place.geometry.location.lng());
    for (let i in place.address_components) {
      let item = place.address_components[i];

      location_obj["formatted_address"] = place.formatted_address;
      if (item["types"].indexOf("locality") > -1) {
        location_obj["locality"] = item["long_name"];
      } else if (item["types"].indexOf("administrative_area_level_1") > -1) {
        location_obj["admin_area_l1"] = item["short_name"];
      } else if (item["types"].indexOf("street_number") > -1) {
        location_obj["street_number"] = item["short_name"];
      } else if (item["types"].indexOf("route") > -1) {
        location_obj["route"] = item["long_name"];
      } else if (item["types"].indexOf("country") > -1) {
        location_obj["country"] = item["long_name"];
      } else if (item["types"].indexOf("postal_code") > -1) {
        location_obj["postal_code"] = item["short_name"];
      }
    }
    return location_obj;
  }

  ngOnInit() {
    const autocomplete = new google.maps.places.Autocomplete(this.element);
    //Event listener to monitor place changes in the input
    google.maps.event.addListener(autocomplete, "place_changed", () => {
      //Emit the new address object for the updated place
      this.onSelect.emit(this.getFormattedAddress(autocomplete.getPlace()));
    });
  }
}

//html就像

 <input
                type="text"
                class="google-place-input"
                google-place
                (onSelect)="setAddress($event)"
                placeholder="Type to search.."
              />

提前致谢

【问题讨论】:

    标签: angular google-maps google-maps-api-3 angular6 googleplacesautocomplete


    【解决方案1】:

    从事件中创建一个 Observable,然后应用 debounceTime 运算符

    import { fromEvent } from 'rxjs';
    import { debounceTime } from 'rxjs/operators';
    
    //create observable that emits 'place_changed' events
    const source = fromEvent(autocomplete, 'place_changed');
    
    //map to string with given event timestamp
    const example = source.pipe(debounceTime(4000));
    
    const subscribe = example.subscribe(val => console.log(val));
    

    顺便说一句,4-5 秒太长了。去抖时间是最后一次按键后的时间。

    更新 #1

    尝试在用户输入查询的地方添加以下指令

    去抖时间.directive.ts

    import {AfterViewInit, Directive, ElementRef, forwardRef, Input, OnDestroy, Renderer2} from '@angular/core';
    import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
    import {fromEvent, Subject} from 'rxjs';
    import {debounceTime, takeUntil} from 'rxjs/operators';
    
    // tslint:disable:directive-selector
    @Directive({
      selector: '[debounceTime]',
      providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => DebounceTimeDirective),
        multi: true
      }]
    })
    export class DebounceTimeDirective extends Destroyable implements ControlValueAccessor, AfterViewInit, OnDestroy {
      protected destroyed$ = new Subject<boolean>();
    
      @Input()
      debounceTime: number;
    
      onChange = (_) => {};
      onTouched = () => {};
    
      constructor(private _elementRef: ElementRef, private renderer: Renderer2) {
        super();
      }
    
      ngAfterViewInit() {
        fromEvent(this._elementRef.nativeElement, 'keyup')
          .pipe(
            takeUntil(this.destroyed$),
            debounceTime(this.debounceTime)
          )
          .subscribe((event: any) => {
            this.onChange(event.target.value);
          });
      }
    
      ngOnDestroy(): void {
        this.destroyed$.next(true);
        this.destroyed$.complete();
      }
    
      writeValue(value: any): void {
        const normalizedValue = value === null || value === undefined ? '' : value;
        this.renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
      }
    
      registerOnChange(fn: () => any): void { this.onChange = fn; }
      registerOnTouched(fn: () => any): void { this.onTouched = fn; }
    }
    

    你的模板.html

    <input [debounceTime]="4000" ... />
    

    【讨论】:

    • 我试过这样 const autocomplete = new google.maps.places.Autocomplete(this.element); //事件监听器,用于监控输入中的位置变化 \n //创建可观察到的发出 'place_changed' 事件 const source = fromEvent(autocomplete, 'place_changed'); //映射到给定事件时间戳的字符串 const example = source.pipe(debounceTime(4000)); const subscribe = example.subscribe(val => console.log(val)); // 我在 Observable._subscribe (fromEvent.js:24) 处收到 TypeError: Invalid event target at setupSubscription (fromEvent.js:50) 的错误
    • 非常感谢您抽出宝贵的时间,我得到了逻辑,但我仍然很困惑,我如何将这个输入逻辑与 GOOGle 自动完成 API 一起使用,比如 const autocomplete = new google.maps.places.Autocomplete (this.element); //监听输入中地方变化的事件监听器 google.maps.event.addListener(autocomplete, "place_changed", () => { //为更新的地方发出新的地址对象 this.onSelect.emit(this.getFormattedAddress (autocomplete.getPlace())); });提前致谢
    猜你喜欢
    • 2023-03-22
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 2019-01-17
    • 1970-01-01
    相关资源
    最近更新 更多