【问题标题】:Can't Seem To Save Off Data Returned From Call To http.get() Method in Angular 6似乎无法保存从 Angular 6 中调用 http.get() 方法返回的数据
【发布时间】:2018-07-12 22:16:36
【问题描述】:

全部:

我是 Angular 6 的新手,一直在学习如何使用表格显示数据。我对静态数据没有任何问题——也就是说,数组中的数据是静态定义的,就像在网上到处可见的众多示例中一样。我感到困惑的地方是处理从版本 4 以来 Angular 提供的(新)HttpClient 返回的数据。

我定义了一个具有 5 个属性的对象,所有这些属性都存储在不同服务器上的 MySQL 表中。该服务器上的 PHP 脚本返回一个包含 25 个 JSON 对象的数组,其中定义了这些属性。

我调用这个服务的方法是:

table-demo-components.ts

import { Component, OnInit } from '@angular/core';
import { FltdataHttpService } from '../fltdatahttp.service';

// Sorting support
import { ViewChild } from '@angular/core';    // new decorator
import { MatSort, MatTableDataSource, MatPaginator } from '@angular/material';

// Data are supplied by a service

var FLIGHTS = new Array();

@Component({
  selector: 'app-table-demo',
  templateUrl: './table-demo.component.html',
  styleUrls: ['./table-demo.component.css']
})
export class TableDemoComponent implements OnInit {

  // specify which columns are to show
  displayedColumns: string[] = [
    'flightNum',
    'destinationCity',
    'schedTime',
    'actualTime',
    'remarks'
  ];     // NOTE: these are the columns/properties as strings!

  // this is how you handle sorted data
  flightDataSource = new MatTableDataSource(this.flightDataService.FLIGHTS);       
  //flightDataSource = new MatTableDataSource(FLIGHTS);       // note the difference

  dummyNum: number;

  // Add decorators for sort and pagination
  @ViewChild(MatSort) sort: MatSort;  
  @ViewChild(MatPaginator) paginator: MatPaginator;

  ngOnInit() {

    this.flightDataSource.sort = this.sort;

  }

  // Inject HTTP support - flightDataService - not flightDataSource
  constructor(public flightDataService: FltdataHttpService) {
    console.log(">>> constructor fired; flightDataService = " + flightDataService);
  }

  // Support for pagination - note it comes in this and not ngOnInit()

  ngAfterViewInit() {
    //************************************ 
    // IT MUST BE IN THIS ORDER!
    //************************************ 

    // flightDataSource is set here
    FLIGHTS = this.flightDataService.getFlightData();       // get the actual data first
    console.log(">>> FLIGHTS local = " + FLIGHTS.length);

    this.flightDataSource = new MatTableDataSource(FLIGHTS);   // then pass it to the source       

    this.flightDataSource.paginator = this.paginator;   // then attached the paginator
    this.flightDataSource.sort = this.sort;             // and last, the sort option
  }

}

在其他地方,我定义了一个服务来调用 http.get 方法:

fltdatahttp.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { FlightInfo } from './table-demo/flight-info';

var newFlight;

@Injectable({
  providedIn: 'root'
})
export class FltdataHttpService {

  public httpData: any;                  

  public FLIGHTS: FlightInfo[] = [];

  constructor(public http: HttpClient) { 
    //this.getFlightData();
  }

  public getFlightDataLocally(): FlightInfo[]  {

    console.log(">>> getFlightDataLocally() fired");

    this.FLIGHTS = [
      {flightNum: '145', destinationCity: 'Chicago Midway', schedTime: '17:35', actualTime: 'ON TIME', remarks: 'AMBASSADOR SERVICE'},
      {flightNum: '365', destinationCity: 'Toronto Pearson', schedTime: '17:46', actualTime: 'ON TIME', remarks: 'NON-STOP'},
      {flightNum: '277', destinationCity: 'Montreal Trudeau', schedTime: '17:51', actualTime: 'ON TIME', remarks: 'NON-STOP'},
      {flightNum: '980', destinationCity: 'New York LaGuardia', schedTime: '17:58', actualTime: 'ON TIME', remarks: 'AMBASSADOR SERVICE'},
      {flightNum: '671', destinationCity: 'Los Angeles Intl', schedTime: '18:02', actualTime: 'ON TIME', remarks: 'VIA PHOENIX'},
    ];

    return this.FLIGHTS;

  }

  public getFlightData(): FlightInfo[] {                // timing issue? web lag?

    console.log(">>> getFlightData(): ");

    this.http.get("http://localhost/flights.php", { responseType: 'text' }).subscribe(data => {

      this.httpData = JSON.parse(data);
      console.log(">>> resp = " + data.toString());

      for (var f = 0; f < this.httpData.flights.length; f++) {

        console.log(">>> creating element - " + this.httpData.flights[f].flightNum);

        newFlight = new FlightInfo();
        newFlight.flightNum = this.httpData.flights[f].flightNum; 
        newFlight.destinationCity = this.httpData.flights[f].destinationCity;
        newFlight.schedTime = this.httpData.flights[f].schedTime;
        newFlight.actualTime = this.httpData.flights[f].actualTime;
        newFlight.remarks = this.httpData.flights[f].remarks;

        this.FLIGHTS.push(newFlight);
      }

    });

    // A static array assigning a series of new FlightInfo objects here can be seen
    // by Angular Material, outside the .subscribe() method above. Inside, the same
    // for loop causes NOTHING to happen to the this.FLIGHTS array.

    return this.FLIGHTS;

  }

}

第一个方法,getFlightDataLocally(),按我的预期执行——当 HTML 页面出现时,我看到了五个已定义的对象。

但是当我使用第二种方法 getFlightData() 时,结果表/数组为空。更令人困惑的是,console.log 消息表明了一个对我来说不直观的触发顺序:

控制台输出:

>>> getFlightData():                 table-demo.component.ts:58 
>>> FLIGHTS local = 0                fltdatahttp.service.ts:59 
>>> resp = { "flights" : [
{
   "flightNum" : "345",
   "destinationCity" : "CHICAGO MIDWAY",
   "schedTime" : "09:30",
   "actualTime" : "ON TIME",
   "remarks" : "AMBASSADOR SERVICE"
},
{
   "flightNum" : "712",
   "destinationCity" : "MILWAUKEE",
   "schedTime" : "09:44",
   "actualTime" : "ON TIME",
   "remarks" : "AMBASSADOR SERVICE"
},
{
   "flightNum" : "910",
   "destinationCity" : "CHAMPAIGN/URBANA",
   "schedTime" : "09:56",
   "actualTime" : "ON TIME",
   "remarks" : "AMBASSADOR SERVICE"
},
{
   "flightNum" : "118",
   "destinationCity" : "HOUSTON HOBBY",
   "schedTime" : "10:00",
   "actualTime" : "ON TIME",
   "remarks" : "AMBASSADOR SERVICE"
},
{
   "flightNum" : "627",
   "destinationCity" : "MIAMI",
   "schedTime" : "10:03",
   "actualTime" : "ON TIME",
   "remarks" : "NONSTOP"
},
...
...
}
]} fltdatahttp.service.ts:63 
>>> creating element - 345
    fltdatahttp.service.ts:63 
>>> creating element - 712 
   fltdatahttp.service.ts:63 
>>> creating element - 910 
   fltdatahttp.service.ts:63 
>>> creating element - 118 
   fltdatahttp.service.ts:63 
>>> creating element - 627 
   fltdatahttp.service.ts:63 
...

我期望 getFlightData() 做的是返回一个包含所有 25 个 JSON 对象的数组——但它似乎所做的只是什么都不返回,而且它似乎是某种我无法解决的序列/时间问题把我的头包起来。 .subscribe 的第一个箭头函数中的 data 变量清楚地接收数据,但尝试将其保存到本地变量 this.httpData 没有奏效。

有人能解释一下什么可以成功地从 Angular 脚本调用第二个 Web 服务器,并让返回的任何数据实际保留而不是消失吗?

我这里有什么问题?

谢谢!

【问题讨论】:

    标签: angular http get angular6


    【解决方案1】:

    Angular 的 http.get()http.post() 方法异步处理。

    因此,当 Angular 等待 get 完成它的工作时,Angular 将继续执行下一行代码无需等待

    FLIGHTS 数组被初始化为空。 get 还没有完成 api 调用,所以数组还是空的。 Angular 不会等待 get 完成,因此 Angular 返回了空数组。

    http.gethttp.post 返回 Observables:一个允许您设置回调以在 http 完成时运行的接口。

    因此,只要 http.get 完成,就会调用您的 subscribe 方法。它可能在 300 毫秒或 4 小时内。我们不知道。但是当它完成时,回调被执行。这将导致FLIGHTS 被填充当时

    那么,如何使用 http.get 的结果?

    嗯,你已经成功了一半。每当 api 调用完成时,您就已经填写了 FltdatahttpService.FLIGHTS。所以不用返回FLIGHTS,你可以直接消费。

    例子:

    <div *ngFor="let flight of FltdatahttpService.FLIGHTS"> <div>{{flight.name}}</div> </div>

    Angular 足够聪明,可以知道FltdatahttpService.FLIGHTS 何时发生变化,并会相应地更新 DOM。

    但是,当您在组件中操作结果时,最好直接从服务返回订阅。然后,您可以让任何您喜欢的消费者进行所需的任何额外处理。

    export class FltdataHttpService {
    
        constructor(public http: HttpClient) { 
          private http: HttpClient
        }
    
        public getFlightData(): Observable<Array<FlightInfo> {
    
            //Angular can auto-deserialize JSON into objects for you
            return this.http.get<Array<FlightInfo>>(
                "http://localhost/flights.php",
                { responseType: 'application/json' });
    
            //returning the raw Observable.
            //The consumer can get a copy of the results by adding a subscription.
            //Thus, each consumer can do any extra processing required.
        }
    }
    

    消费者:

    export class TableDemoComponent implements OnInit {
    
        //FLIGHTS won't be filled until the service call finishes.
        public flightDataSource = new MatTableDataSource(new Array<FlightData>());
    
        @ViewChild(MatSort) sort: MatSort;
        @ViewChild(MatPaginator) paginator: MatPaginator;
    
        ngOnInit() {
            //Init stuff here
        }
    
        constructor(
          public flightDataService: FltdataHttpService
        ) { }
    
        ngAfterViewInit() {
            //Start the service call.
            //Do stuff when it finishes.
    
            this.flightDataService.getFlightData()
                .subscribe(
                   flightData => this.onFlightDataChanged(flightData),
                   error => this.onError(error)
                 );
        }
    
        private onFlightDataChanged(flightData: Array<FlightData>): void {
            //the service call has finished.
            //Recreating the table using the fresh data from the service
    
            this.flightDataSource = new MatTableDataSource(flightData);
            this.flightDataSource.paginator = this.paginator;
            this.flightDataSource.sort = this.sort;
        }
    
        private onError(error: any): void {
            //something broke.
            console.log(error);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-27
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多