web-dev-qa-db-ja.com

プロパティ「json」はタイプ「Object」に存在しません

アンギュラー2 HttpClientでREST経由でデータを取得しようとしています。私はここで角度のチュートリアルに従っています https://angular.io/tutorial/toh-pt6ヒーローとHTTPセクションでは、httpを介してヒーローデータを取得するために使用されるこのコードスニペットが表示されます。

getHeroes(): Promise<Hero[]> {
  return this.http.get(this.heroesUrl)
         .toPromise()
         .then(response => response.json().data as Hero[])
         .catch(this.handleError);
}

そして、以下は私のアプリケーションで書いた同様のバージョンです

fetch(startIndex: number, limit: number): Promise<Order[]> {
    let url = this.baseUrl + "&startIndex=" + startIndex + "&limit=" + limit;

    return this.http.get(url)
                .toPromise()
                .then(response => response.json().results as Order[])
                .catch(this.handleError);
}

InteliJ Ideaを使用していますが、response.json()呼び出しに赤い線があり、ng buildを使用してビルドしようとしてもエラー。

プロパティ 'json'はタイプ 'Object'に存在しません。

json().dataの代わりにjson().resultsがあります。チュートリアルによれば、サーバーはdataフィールドを持つオブジェクトで応答しましたが、自分のサーバーはresultsフィールドを持つオブジェクトで応答するためです。チュートリアルを少し下にスクロールすると、このポイントが表示されます。

サーバーが返すデータの形状に注意してください。この特定のインメモリWeb APIの例は、データプロパティを持つオブジェクトを返します。あなたのAPIは何か他のものを返すかもしれません。 Web APIに合わせてコードを調整します。

これを修正するために、私はこのようなことを試みました

(response: Response) => response.json().results as Order[]

私がそれをしたとき、.json()メソッドは解決されましたが、別のエラーがポップアップしました

タイプPromiseにはプロパティ結果が存在しません

インターフェースを定義することでそれを修正しようとしました

interface OrderResponse {
    orders: Order[];
}

そしてget呼び出しを修正しました

 .get<OrderResponse>(url)...

しかし、それもうまくいきませんでした。別のエラーがポップアップしました

タイプ「OrderResponse」は、タイプ「Response」に割り当てることができません。

1つの注意点は、チュートリアルではAngular HttpModuleを使用しましたが、私のアプリケーションでは新しいAngular HttpClientModuleを使用しているため、エラーが発生する可能性があることです。

私はAngular 2が初めてであり、これを使用して作成する最初のアプリです。上記のコードが新しいHttpClientModuleで無効になった場合、新しいHttpClientModuleで同じことを達成する方法についての助けをいただければ幸いです。

私は同様の質問を見つけました プロパティ 'json'はタイプ '{}'に存在しません および プロパティはタイプ 'オブジェクト'に存在しません しかし、そこの答えは私を助けませんでした。

更新

コメントが示唆したように、新しいHttpClientModuleには.json()メソッドはありません。新しいモジュールで同じ効果を達成する方法については、まだ感謝しています。ガイドから、彼らはこのようなことをしました

http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

私は完全に理解していますが、私の問題は、コードがコンポーネント内ではなくサービス内にあるため、subscribeを呼び出して結果をインスタンスフィールドに割り当てることはあまり意味がないことです。

PromiseにラップされたOrderの配列を返すサービスが必要です。私のコンポーネントは次のような呼び出しを行うことができます

this.orderService.fetch(0, 10).then(orders => this.orders = orders)

また、サービスフェッチメソッドでローカル変数を宣言して、

.subscribe(data => {
    this.orders = data.results;
}
// and out of the get call I return my local variable orders like
return Promise.resolve(orders)

しかし、これは.get()の呼び出しが非同期であり、すべてのデータがフェッチされ、orders配列が空になる前にメソッドが返される可能性があるため、あまり意味がありません。

更新

ここに要求されているのは、handleErrorのコードです

private handleError(error: any): Promise<any> {
    console.log('An error occured ', error);
    return Promise.reject(error.message || error);
}
31
ivange94

更新:rxjs> v5.5の場合

いくつかのコメントや他の回答で述べたように、デフォルトでは HttpClient は応答のコンテンツをオブジェクトにデシリアライズします。一部のメソッドでは、結果をダックタイプするためにジェネリック型引数を渡すことができます。これがjson()メソッドがもうない理由です。

import {throwError} from 'rxjs';
import {catchError, map} from 'rxjs/operators';

export interface Order {
  // Properties
}

interface ResponseOrders {
  results: Order[];
}

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get<ResponseOrders >(this.baseUrl,{
       params
    }).pipe(
       map(res => res.results || []),
       catchError(error => _throwError(error.message || error))
    );
} 

toPromise()を呼び出すだけで、返されたObservablePromiseに簡単に変換できることに注意してください。

元の回答:

あなたの場合、次のことができます

バックエンドが次のようなものを返すと仮定します:

{results: [{},{}]}

jSON形式では、すべての{}はシリアル化されたオブジェクトであり、次のものが必要です。

// Somewhere in your src folder

export interface Order {
  // Properties
}

import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { Order } from 'somewhere_in_src';    

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get(this.baseUrl,{
       params
    })
    .map(res => res.results as Order[] || []); 
   // in case that the property results in the res POJO doesnt exist (res.results returns null) then return empty array ([])
  }
} 

これはHTTPインターセプターを介してアーカイブできるため、catchセクションを削除しました。 ドキュメント を確認してください。例として:

https://Gist.github.com/jotatoledo/765c7f6d8a755613cafca97e83313b9

消費するには、次のように呼び出すだけです。

// In some component for example
this.fooService.fetch(...).subscribe(data => ...); // data is Order[]
9
Jota.Toledo

将来の訪問者のために:新しい HttpClient (Angular 4.3+)では、responseオブジェクトはデフォルトでJSONなので、response.json().dataを実行する必要はありませんもう。 responseを直接使用するだけです。

(公式ドキュメントから修正):

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

@Component(...)
export class YourComponent implements OnInit {

  // Inject HttpClient into your component or service.
  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.http.get('https://api.github.com/users')
        .subscribe(response => console.log(response));
  }
}

それをインポートし、プロジェクトのapp.module.tsimportsの下にモジュールを含めることを忘れないでください。

...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module after BrowserModule.
    HttpClientModule,
    ...
  ],
  ...
94
Voicu

将来の訪問者向け:新しいHttpClient(Angular 4.3以降)では、応答オブジェクトはデフォルトでJSONであるため、response.json()。dataを行う必要はありません。応答を直接使用するだけです。

0