使用typescript作为自定义数据类型返回Angular中的Promise

时间:2017-06-18 22:51:57

标签: javascript json angular typescript

我是Typescript中的新手,我正在尝试使用Device类型的对象返回一个承诺,但我无法达到它。

问题是,当我返回Mock时,一切正常,但是当我连接到真正的API时,我遇到了问题response.json().data as Device

当我在服务器中询问数据然后我尝试在模板中打印它时,它已经消失了,在控制台中我有Undefined。 另外,函数console.logdevice.component.ts中的getDevices()打印就像对象的旧状态一样,因为当我更改数据时,会显示之前应该显示的数据。

我有几个问题,如:

  1. 如何访问承诺的response.json().data中的.then,以查看结构的内容或数据的含义?

  2. 我如何映射(我认为这个术语对于Observable是正确的,但我不知道如何对Promise s device我的import { Component, OnInit, Input } from '@angular/core'; import { Device } from './device'; import { DeviceService } from './device.service'; @Component({ selector: 'app-device', templateUrl: './device.component.html' }) export class DeviceComponent implements OnInit { @Input() private device: Device; constructor(private deviceService: DeviceService) {}; ngOnInit(): void { // this.getDevice(40072); this.deviceService.getDeviceMock().then(device => this.device = device); } getDevice(id: number): void { this.deviceService.getDevice(id).then(device => this.device = device); console.log(this.device); // this.deviceService.getDeviceMock().then(device => this.device = device); } search(id: number): void { this.getDevice(id); } save(): void { this.deviceService.setDevice(this.device); } } 对象说出来API的数据?

  3. device.component.ts

    <input [(ngModel)]="idSearch" type="text" placeholder="Insert ID"  >
    <button (click)="search(idSearch)">Search</button>
    
    <div *ngIf="device">
    <div>
      <label>Uid: </label>
      <input [(ngModel)]="device.Uid" placeholder="Uid">
    </div>
    
    <div>
      <label>VigilId: </label>
    <input [(ngModel)]="device.VigilId" placeholder="VigilId">
    </div>
    
    <div>
      <label>CmfPhoneNumber: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.CmfPhoneNumber" placeholder="CmfPhoneNumber">
    </div>
    
    <div>
      <label>ReportInterval: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.ReportInterval" placeholder="ReportInterval">
    </div>
    
    <div>
      <label>GeoLocationHighAccuracy: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.GeoLocationHighAccuracy" placeholder="GeoLocationHighAccuracy">
    </div>
    
    <div>
      <label>AlarmCancelTimeout: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.AlarmCancelTimeout" placeholder="AlarmCancelTimeout">
    </div>
    
    <div>
      <label>AdherenceCheckInterval: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.AdherenceCheckInterval" placeholder="AdherenceCheckInterval">
    </div>
    
    <div>
      <label>PreAlarmPeriod: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.PreAlarmPeriod" placeholder="PreAlarmPeriod">
    </div>
    
    <div>
      <label>PingInterval: </label>
      <input [(ngModel)]="device.Model.RuntimeSettings.PingInterval" placeholder="PingInterval">
    </div>
    
    <button (click)="save()">Send</button>
    

    device.component.html

    import { Component } from '@angular/core';
    import { Device } from './device';
    import { Injectable } from '@angular/core';
    import { Headers, Http } from '@angular/http';
    import 'rxjs/add/operator/toPromise';
    
    import { DeviceMock } from './device-mock'
    
    
    @Injectable()
    export class DeviceService {
        // TODO: Create configuration file.
        private apiUrl = 'https://api.com/api2/v2';
        private headers = new Headers({'Authorization': 'xxxx'});
    
        constructor(private http: Http) {};
        getDeviceMock(): Promise<Device> {
            return Promise.resolve(DeviceMock)
        }
    
        getDevice(id: number): Promise<Device> {
            const url = `${this.apiUrl}/device/${id}?names=RuntimeSettings`;
            return this.http.get(url, {headers: this.headers})
                .toPromise()
                .then(response => response.json().data as Device)
                .catch(this.handleError);
        }
    
        setDevice(device: Device): Promise<Device> {
            this.headers.set('Content-Type', 'application/json');
            const url = `${this.apiUrl}/device/${device.VigilId}?names=RuntimeSettings`;
            return this.http.put(url, JSON.stringify(device), {headers: this.headers})
                .toPromise()
                .then(response => response.json().data as Device)
                .catch(this.handleError);
        }
    
        private handleError(error: any): Promise<any> {
            console.error('An error occurred', error);
            return Promise.reject(error.message || error);
        }
    };
    

    device.service.ts

    export interface Device {
        VigilId: number;
        Uid: string;
        Model: Model;
    };
    
    interface Model {
        RuntimeSettings: RuntimeSettings;
    };
    
    interface RuntimeSettings {
        ReportInterval: number;
        PingInterval: number;
        PreAlarmPeriod: number;
        AdherenceCheckInterval: number;
        AlarmClearTimeout: number;
        AlarmCancelTimeout: number;
        DailyReportInterval: number;
        GeoLocationRetryCount: number;
        GeoLocationHighAccuracy: true;
        GeoLocationTimeOut: number;
        GeoMaxAgeTimeOut: number;
        CmfPhoneNumber: number;
        PalmTouchTrigger: boolean;
        TouchTriggerCooldownPeriod: number;
        DemoMode: boolean;
        DeviceName: string;
        VerboseLogging: boolean;
    };
    

    device.ts

    {
        "VigilId": 41,
        "Uid": "Identi",
        "Model": {
            "RuntimeSettings": {
                "ReportInterval": 900,
                "PingInterval": 300,
                "PreAlarmPeriod": 10,
                "AdherenceCheckInterval": 3600,
                "AlarmClearTimeout": 600,
                "AlarmCancelTimeout": 15,
                "DailyReportInterval": 43200,
                "GeoLocationRetryCount": 3,
                "GeoLocationHighAccuracy": true,
                "GeoLocationTimeOut": 5000,
                "GeoMaxAgeTimeOut": 60,
                "CmfPhoneNumber": "",
                "PalmTouchTrigger": true,
                "TouchTriggerCooldownPeriod": 30,
                "DemoMode": false,
                "DeviceName": "",
                "VerboseLogging": false
            }
        }
    }
    

    这是API的回复

    level

2 个答案:

答案 0 :(得分:2)

问题(1):

您必须注意到HTTP客户端请求是异步的。这意味着外部/父功能不等待网络请求完成,即不阻止。这就是你在getDevices上获得“旧数据”的原因:它在从服务器响应更新之前打印对象。

getDevice(id: number): void {
    this.deviceService.getDevice(id)
        .then(device => this.device = device);  // network request is scheduled
    console.log(this.device); // device is printed to log but not necessarily
                              // after the network request returns
}

要解决此问题,请将其更改为:

getDevice(id: number): void {
    this.deviceService.getDevice(id).then(device => {
        console.log(device); // print to console what is returned from network
        this.device = device;
    });
}

问题(2):

您正在执行的操作this.device = device是正确的,它将更新您的this.device对象并将其从服务器响应指向新的device对象。 (除非我错误地理解了这个问题)。

答案 1 :(得分:1)

关于你的第二个问题,这一行:

response.json().data

似乎正在寻找名为“data”的JSON属性,但我在你的例子中没有看到任何地方。返回的JSON是否具有名为data?

的属性