Angular .subscribe выполняется в конце после ngOnInit - PullRequest
0 голосов
/ 29 апреля 2020

Я новичок в angular. Я пытаюсь код ниже, чтобы заполнить диаграмму ap ie. Я присваиваю значения внутри конструктора. Но здесь метод .subscribe выполняется в конце после выполнения ngOnInit (). И он отображает значение undefined в качестве значения this.TestVar

cities: Observable<DataModel>;
TestVar: string;

constructor(private http: HttpClient) {

this.cities = this.http.get<DataModel>('./assets/data.json');

    this.cities.subscribe(events => {
      this.TestVar = events[0].District;
    });
}
ngOnInit() {
    let chart = new CanvasJS.Chart("chartContainer", {
        theme: "light2",
        animationEnabled: true,
        exportEnabled: true,
        title:{
            text: "Monthly Expense"
        },
        data: [{
            type: "pie",
            showInLegend: true,
            toolTipContent: "<b>{name}</b>: ${y} (#percent%)",
            indexLabel: "{name} - #percent%",
            dataPoints: [
                { y: 450, name: this.TestVar },
                { y: 120, name: "Insurance" },
                { y: 300, name: "Traveling" },
                { y: 800, name: "Housing" },
                { y: 150, name: "Education" },
                { y: 150, name: "Shopping"},
                { y: 250, name: "Others" }
            ]
        }]
    });

    chart.render();
}

Я даже пытался добавить приведенный ниже код в ngOnInit (). Но это не решило мою проблему.

this.cities.subscribe(events => {
      this.TestVar = events[0].District;
});

Спасибо, если кто-нибудь может мне помочь с этим.

Ответы [ 3 ]

1 голос
/ 29 апреля 2020

Observables равны async, что означает, что вы пытаетесь использовать значение this.TestVar до того, как ваш http-запрос завершен, и поэтому все еще не определено.

Вы можете оставаться синхронным, если вы инициализируете график после окончания наблюдения:

 cities: Observable<DataModel>;
    TestVar: string;

    constructor(private http: HttpClient) {
        this.cities.subscribe(events => {
          this.TestVar = events[0].District;
          this.init();
        });
    }

    ngOnInit() {
       this.cities = this.http.get<DataModel>('./assets/data.json');
    }

public init(): void {
let chart = new CanvasJS.Chart("chartContainer", {
            theme: "light2",
            animationEnabled: true,
            exportEnabled: true,
            title:{
                text: "Monthly Expense"
            },
            data: [{
                type: "pie",
                showInLegend: true,
                toolTipContent: "<b>{name}</b>: ${y} (#percent%)",
                indexLabel: "{name} - #percent%",
                dataPoints: [
                    { y: 450, name: this.TestVar },
                    { y: 120, name: "Insurance" },
                    { y: 300, name: "Traveling" },
                    { y: 800, name: "Housing" },
                    { y: 150, name: "Education" },
                    { y: 150, name: "Shopping"},
                    { y: 250, name: "Others" }
                ]
            }]
        });

        chart.render();
}
0 голосов
/ 29 апреля 2020

TL; DR

Позвоните по коду, чтобы создать и обработать ваш chart после , когда вы получили данные от вашего http.get вызова.

Более длинная версия

TestVar не определена, потому что вы пытаетесь использовать значение до того, как оно будет заполнено вашей функцией обратного вызова subscribe.

Observable с потоком данных асинхронно (не для путать с async / await с обещаниями). Прочитайте Rx Js Документы , чтобы ознакомиться с тем, как они работают и как их использовать.

Ваш http.get вызов возвращает данные после того, как вы уже создал и визуализировал график. В какое время при создании / рендеринге значение TestVar по-прежнему равно undefined, поскольку оно еще не установлено.

Вам необходимо установить TestVar значение внутри обратный вызов и , затем используйте код, который вы используете для настройки и визуализации диаграммы, например:

TestVar: string;

constructor(private readonly _http: HttpClient) { }

ngOnInit() {
  this._http.get<DataModel>('./assets/data.json')
    .subscribe(data => {
      this.TestVar = data[0].District;

      // code to render chart AFTER you've retrieved the value
    });
}

Обратите внимание, что вам не нужно создавать и назначать cities переменная класса Observable<DataModel>, так как вы используете ее только локально и нигде больше, и вместо этого можете «связать» вызов с возвращенным Observable, чтобы подписаться на нее.

Обратите внимание, что это желательно создавать и подписываться на вещи внутри ngOnInit(), а не в конструкторе. ngOnInit ловушка жизненного цикла указывает, что Angular создал компонент, и все привязки готовы, поэтому вы не создаете все вещи внутри него, прежде чем Angular сможет что-либо отобразить. Вот гораздо лучшее объяснение на SO о различиях между constructor и ngOnInit.


Еще лучше:

Вы используете только TestVar значение один раз / локально, поэтому я не вижу необходимости устанавливать его как переменную класса (как с переменной класса cities).

Вместо этого просто возьмите значение и используйте его внутри Ваш обратный вызов:

// no need for the TestVar inside the class

constructor(private readonly _http: HttpClient) { }

ngOnInit() {
  this._http.get<DataModel>('./assets/data.json')
    .subscribe(data => {
      const district = data[0].District;

      // use the district variable when setting up your chart
    });
}

Еще лучше:

Извлеките код создания диаграммы в свою собственную функцию внутри вашего класса, которая принимает значение District в качестве ввода, чтобы ваш код был красивым и чистым, вместо того, чтобы иметь большую длинную функцию ngOnInit().

Это сделает ваш код намного более читабельным и будет легче видеть, что происходит:

ngOnInit() {
  this._http.get<DataModel>('./assets/data.json')
    .subscribe(data => {
      const district = data[0].District;

      // then set up the chart
      this.initializeChart(district);
    });
}

private initializeChart(district: string) {
  // your code to initialize chart, using the district param passed in
}
0 голосов
/ 29 апреля 2020

Попробуйте вместо этого, добавив создание и рендеринг диаграммы в блок asyn c наблюдаемого:

cities: Observable<DataModel>;
TestVar: string;

constructor(private http: HttpClient) { }

ngOnInit() {
  this.cities = this.http.get<DataModel>('./assets/data.json');

  this.cities.subscribe(events => {
    this.TestVar = events[0].District;

    let chart = new CanvasJS.Chart("chartContainer", {
      theme: "light2",
      animationEnabled: true,
      exportEnabled: true,
      title: {
        text: "Monthly Expense"
      },
      data: [{
        type: "pie",
        showInLegend: true,
        toolTipContent: "<b>{name}</b>: ${y} (#percent%)",
        indexLabel: "{name} - #percent%",
        dataPoints: [
          { y: 450, name: this.TestVar },
          { y: 120, name: "Insurance" },
          { y: 300, name: "Traveling" },
          { y: 800, name: "Housing" },
          { y: 150, name: "Education" },
          { y: 150, name: "Shopping" },
          { y: 250, name: "Others" }
        ]
      }]
    });

    chart.render();
  });

}
...