Angular 6 Область подписки - переменные не могут быть назначены

У меня есть компонент карты, использующий API-интерфейс mapbox, который зависит от долготных и широтных координат, возвращаемых геокодером.

Есть служба, которая вызывает конечную точку с некоторыми параметрами. Я подписываюсь на эту услугу и использую функцию стрелки, как показано в коде ниже. Хотя я ожидаю, что ответ будет назначен this.geocodeResponse, а также соответствующим this.longitude и this.latitude, эти переменные остаются пустыми вне области действия функции. Я знаю это, потому что получаю этот ответ от браузера ERROR Error: "Invalid LngLat object: (NaN, NaN)". Я подтвердил этот результат, зарегистрировав ответы в console.info и убедившись, что три ответа остаются пустыми.

Я знаю, что служба работает, потому что она была протестирована и дает правильный ответ в другом месте.

Вот соответствующий код:

import { Component, OnInit, ViewChild, ElementRef, Input } from "@angular/core";

import mapboxgl from "mapbox-gl";

import { GeocodingService } from "../geocoding.service";
import { environment } from "../../../environments/environment";

@Component({
  selector: "app-dynamic-map",
  templateUrl: "./dynamic-map.component.html",
  styleUrls: ["./dynamic-map.component.css"]
})
export class DynamicMapComponent implements OnInit {
  @Input() queryString: String
  geocodeResponse: any;
  longitude: string;
  latitude: string;

  map: mapboxgl.Map;
  @ViewChild("mapElement") mapElement: ElementRef;
  constructor(private geocodingService: GeocodingService) {}

  ngOnInit() {
    mapboxgl.accessToken = environment.mapbox.accessToken;

    this.geocodingService.getGeoCords(this.queryString).subscribe(response => {
      this.geocodeResponse = response;
      this.longitude = this.geocodeResponse.features[0].bbox[0],
      this.latitude = this.geocodeResponse.features[0].bbox[1]
  });
  }

  /* Given a query string, get the first result of a places query from api and pass to
   * the dynamic map centering on coordinates */
  ngAfterViewInit() {

    /* THESE REMAIN UNASSIGNED HERE */
    console.info(this.geocodeResponse)
    console.info(this.longitude)
    console.info(this.latitude)

    this.map = new mapboxgl.Map({
      container: this.mapElement.nativeElement,
      style: "mapbox://styles/mapbox/streets-v9",
      center: [this.longitude, this.latitude],
      zoom: 12
    });
  }
}

Я знаю, что проблема заключается в подписке на услугу. Возможно, я не совсем понимаю, как Angular обрабатывает подписку и область действия переменной ответа.

Ожидаемое поведение — непустые переменные вне ответа на подписку. Более того, я наблюдал такое поведение в отладчике firefox, но без запуска тегов в отладчике переменные остаются неназначенными.

Я могу предоставить дополнительный код и вывод журнала, если это необходимо. Уточните, пожалуйста, что необходимо для диагностики проблемы. Кроме того, хотя явное решение проблемы — это хорошо, мне бы очень хотелось понять, почему возникает эта проблема, потому что у меня есть несколько других компонентов, которые имеют аналогичные проблемы.

Это произошло потому, что .subscribe — асинхронная функция.

Josef Katič 12.03.2019 20:56

Возможный дубликат Как вернуть ответ на асинхронный вызов?

Igor 12.03.2019 20:57
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
107
1

Ответы 1

Проблема с компонентом в том, что он полагается на данные, которые ему сначала нужно получить от асинхронной операции. Есть 2 распространенных способа обойти это:

  1. Инициализируйте критические значения значениями по умолчанию в вашем компоненте. Когда компонент получит ответ от асинхронного вызова, значения будут обновлены.
  2. Используйте индикатор в компоненте, чтобы проверить, был ли обработан асинхронный ответ или нет. Проверьте эти значения, где это применимо, в любых вызовах методов машинописного текста и скройте HTML в шаблоне, где HTML зависит от значений из службы.

Вот некоторый код, который иллюстрирует вышеуказанные пункты. Не весь ваш код дублируется ниже.

Значения по умолчанию

export class DynamicMapComponent implements OnInit {
  longitude: string;
  latitude: string;

  constructor(private geocodingService: GeocodingService) {
    this.longitude = '0';
    this.latitude = '0';
  }

  ngOnInit() {
    mapboxgl.accessToken = environment.mapbox.accessToken;

    this.geocodingService.getGeoCords(this.queryString).subscribe(response => {
      this.geocodeResponse = response;
      this.longitude = this.geocodeResponse.features[0].bbox[0];
      this.latitude = this.geocodeResponse.features[0].bbox[1];
    });
  }

Индикатор

export class DynamicMapComponent implements OnInit {
  longitude: string;
  latitude: string;
  isInitialized: boolean = false;

  constructor(private geocodingService: GeocodingService) {
  }

  ngOnInit() {
    mapboxgl.accessToken = environment.mapbox.accessToken;

    this.geocodingService.getGeoCords(this.queryString).subscribe(response => {
      this.geocodeResponse = response;
      this.longitude = this.geocodeResponse.features[0].bbox[0];
      this.latitude = this.geocodeResponse.features[0].bbox[1];
      this.isInitialized = true;
    });
  }

динамическая карта.component.html

<div *ngIf = "isInitialized">
  <p>dependent html here</p>
</div>

См. также Как вернуть ответ на асинхронный вызов? для получения дополнительной информации об асинхронных вызовах в javascript.

Есть ли способ принудительно обновить решение (1)? Карта загружается с координатами по умолчанию, однако долгота и широта никогда не обновляются.

user9961979 14.03.2019 16:51

@Secaucus - вы могли бы, но я не знаю, как вы запускаете его для загрузки, это действительно зависит от API и от того, можете ли вы вызвать его из javascript. Я бы проверил их документацию. В качестве альтернативы просто используйте решение 2 и подождите, пока вы не получите ответ от API, прежде чем загружать html для этого элемента управления.

Igor 14.03.2019 17:05

Другие вопросы по теме