Неправильный стиль Ng-Bootstrap Typeahead с автозаполнением мест Google Maps

Я разрабатываю приложение Angular 4, которое использует директиву Ng-Bootstrap typeahead. В примере с Википедией они делают вызов API к Википедии и отображают результаты в поле ввода. Я пытаюсь сделать то же самое, но вместо этого использую службу автозаполнения Google Maps.

Следуя примеру из Википедии, я создал аналогичный сервис, который возвращает Observable Rxjs, содержащий автозаполненные места.

search(term: string) {
    if (term === '') {
      return Observable.of([]);
    }

    return Observable.create(observer => {
        this.autocompleteService.getPlacePredictions({ input: term }, (results, status) => {
          if (status == google.maps.places.PlacesServiceStatus.OK) {
            observer.next(results.map(result => result.description));
            observer.complete();
          } else {
            console.log('Error - ', results, ' & Status - ', status);
            observer.next({});
            observer.complete();
          }
        });
    });
}

На стороне контроллера мой код выглядит так:

search = (text$: Observable<string>) =>
    text$
        .debounceTime(300)
        .distinctUntilChanged()
        .switchMap(term =>
            this.service.search(term)
                .do(() => this.searchFailed = false)
                .catch(() => {
                    this.searchFailed = true;
                    return Observable.of([]);
                }))

Это работает хорошо, но по какой-то причине полоса ввода появляется в неправильном месте, пока что-то не вызовет перерисовку.

Обратите внимание на пробел между полем ввода и текстом на верхнем изображении

Нажатие любой клавиши или щелчок в любом месте экрана мгновенно исправляет это, но я не могу понять, как это исправить с первого раза.

Из моего исследования кажется, что это может быть проблема со службой автозаполнения мест Google Maps, работающей за пределами NgZone и не вызывающей перерисовку, но мне не повезло ни с одной из обычных стратегий принудительной перерисовки вручную (ApplicationRef. tick(), NgZone.run(), ChangeDetectorRef.detectChanges()).

Любые предложения будут ценны!

Изменить: плункер с похожим поведением: https://embed.plnkr.co/iy2Zhd5rEhBK2aVbBqsB/


person Collin Dutter    schedule 15.08.2017    source источник
comment
Обычно NgZone.run() должен помочь. Не могли бы вы собрать плунжер, который воспроизводит проблему, чтобы мы могли посмотреть?   -  person pkozlowski.opensource    schedule 15.08.2017
comment
Где бы вы порекомендовали выполнить NgZone.run()?   -  person Collin Dutter    schedule 15.08.2017
comment
В месте, где осуществляется вызов внешнего API (карты Google). Опять же, наличие плункера со сценарием воспроизведения позволило бы нам найти ответ намного быстрее :-)   -  person pkozlowski.opensource    schedule 15.08.2017
comment
Таким образом, я получаю почти то же самое поведение в plunker, за исключением того, что вместо того, чтобы ввод текста смещался до события, он просто не появляется вообще до события. Попробуйте ввести один символ, подождать секунду, а затем нажать что-то вроде клавиши Shift. Шрифт появляется только тогда. embed.plnkr.co/iy2Zhd5rEhBK2aVbBqsB   -  person Collin Dutter    schedule 15.08.2017


Ответы (1)


Я понял! В итоге NgZone помог, но мне пришлось поместить его внутри обратного вызова, а не обернуть его.

search(term: string) {
  if (term === '') {
    return Observable.of([]);
  }

  let result = Observable.create(observer => {
    this.autocompleteService.getPlacePredictions({ input: term }, (results, status) => {
      this.ngZone.run(() => {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
          observer.next(results.map(result => result.description));
          observer.complete();
        } else {
          console.log('Error - ', results, ' & Status - ', status);
          observer.next({});
          observer.complete();
        }
      });
    });
  });
  return result;
}
person Collin Dutter    schedule 15.08.2017