переменная не определена вне подписки при использовании http - PullRequest
0 голосов
/ 18 мая 2018

Я работаю над проектом Angular 2, и у меня есть служба MockService с методом getMockData (), который используется в моем компоненте следующим образом:

import { Component, OnInit } from '@angular/core';
import { Mock } from './mock';
//import { MOCK } from './mock-data';
import { MockService } from '../mock.service';
import { Chart } from 'chart.js';
import 'chart.piecelabel.js';

@Component({
  selector: 'app-viz',
  templateUrl: './viz.component.html',
  styleUrls: ['./viz.component.scss']
})
export class VizComponent implements OnInit {
  mock:Mock;

  options = {
    responsive: true,
    tooltips: {
      enabled: false
    },
    legend: {
      display: false
    },
    pieceLabel:{
      render: 'percetage',
      precision: 0,

      // identifies whether or not labels of value 0 are displayed, default is false
      showZero: true,

      // font size, default is defaultFontSize
      fontSize: 12,

      // font color, can be color array for each data or function for dynamic color, default is defaultFontColor
      fontColor: ['green', 'blue'],

      // font style, default is defaultFontStyle
      fontStyle: 'normal',

      // font family, default is defaultFontFamily
      fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",

      // draw text shadows under labels, default is false
      textShadow: true,

      // text shadow intensity, default is 6
      shadowBlur: 10,

      // text shadow X offset, default is 3
      shadowOffsetX: -5,

      // text shadow Y offset, default is 3
      shadowOffsetY: 5,

      // text shadow color, default is 'rgba(0,0,0,0.3)'
      shadowColor: 'rgba(255,0,0,0.75)',

      // draw label in arc, default is false
      arc: false,

      // position to draw label, available value is 'default', 'border' and 'outside'
      // default is 'default'
      position: 'outside'
    }
  }

  constructor(private mockService: MockService) {
  }

  ngOnInit() {
    this.getData();

    let ctx = "myChart";
    let myChart = new Chart(ctx,{
      type: this.mock.type,
      data: this.mock.data,
      options: this.options
    })
  }

  getData(): void {
    this.mockService.getMockData()
    .subscribe(mock_data => {
       this.mock = mock_data;
    });
  }
}

иMockService 'выглядит следующим образом:

import { Injectable } from '@angular/core';
import { Mock } from './viz/mock';
import { MOCK } from './viz/mock-data';
import { Observable} from 'rxjs';
import { of } from 'rxjs/observable/of';
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable()
export class MockService {
  private mockUrl = 'api/MOCK';

  constructor(
    private http: HttpClient
  ) { }

  getMockData(): Observable<Mock> {
    //return of(MOCK);
    return this.http.get<Mock>(this.mockUrl);
  }

}

Проблема заключается в том, что когда я использую оператор' of 'для возврата данных, код не прерывается и диаграмма отображается, как и ожидалось.Но когда я использую метод http.get, свойство mock в моем компоненте становится неопределенным.Он определяется внутри метода подписки.Я могу использовать консоль для входа в систему.Но везде вне метода, даже в методе getData (), он не определен.Как я могу использовать метод http.get для достижения той же функциональности, что и раньше?

Ответы [ 4 ]

0 голосов
/ 18 мая 2018

Наблюдаемое является асинхронным, поэтому оно не завершилось при инициализации Chart.Вы можете дождаться окончания наблюдаемого, преобразовав его в обещание и используя async / await

async ngOnInit() {
    this.mock = await this.getData();
    ...
}

и метод getData ():

  getData(): Promise<Mock> {
    return this.mockService.getMockData().toPromise();
  }
0 голосов
/ 18 мая 2018

попробуй:

ngOnInit() {
    let ctx = "myChart";
    this.mockService.getMockData()
    .subscribe(mock_data => {
      this.mock = mock_data;
      let myChart = new Chart(ctx,{
      type: mock_data.type,
      data: mock_data.data,
      options: this.options
    })
    });
  }
0 голосов
/ 18 мая 2018

Если вы попытаетесь использовать this.mock до подписки, она будет неопределенной.Потому что, когда вы загружаете данные с помощью http-запроса, перед выполнением кода подписки возникает задержка.

Поэтому я предлагаю создать метод refresh (), который вы вызываете из подписки, который обновляет другойобъекты, на которые опирается this.mock.

Что-то вроде этого может быть:

getData(): void {
  this.mockService.getMockData()
  .subscribe(mock_data => {
    this.mock = mock_data;
    this.refresh();
  });
}

refresh() {
  let myChart = new Chart(ctx,{
    type: this.mock.type,
    data: this.mock.data,
    options: this.options
  })
}
0 голосов
/ 18 мая 2018

ваша проблема в том, что http.get является асинхронным

, попробуйте что-то вроде этого:

  getData(): Promise<Mock> {
    return new Promise(r => {
      this.mockService.getMockData()
        .subscribe(mock_data => {
           r(mock_data);
        });
    });
  }

и затем в вашем ngOnInit

  ngOnInit() {
    this.getData().then((mock) => {
      this.mock = mock;
      let ctx = "myChart";
      let myChart = new Chart(ctx,{
        type: this.mock.type,
        data: this.mock.data,
        options: this.options
      })
    });
  }

, если вычтобы ваш код был более читабельным, вы также можете использовать синтаксис async / await, например:

ngOnInit() {
  (async () => {
    this.mock = await this.getData();
    ...
  })();
}

при заметке angular вы не должны использовать циклические функции (например, OnInit), такие как:

// NOT LIKE THIS
async ngOnInit() { ... }
// or
ngOnInit = async function() { ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...