wake-up-neo.com

Die Eigenschaft 'json' ist beim Typ 'Object' nicht vorhanden

Ich versuche, Daten über REST mit eckigen 2 HttpClient abzurufen. Ich verfolge das eckige Tutorial hier https://angular.io/tutorial/toh-pt6 und im Abschnitt Heroes and HTTP sehen Sie dieses Codefragment, das zum Abrufen von Heldendaten über verwendet wird http.

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

Und unten ist eine ähnliche Version, die ich in meinem Antrag geschrieben habe

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);
}

Ich verwende InteliJ Idea und der Anruf response.json () weist eine rote Linie auf. Selbst wenn ich versuche, mit ng build zu bauen, erhalte ich den Fehler.

Die Eigenschaft 'json' ist für den Typ 'Object' nicht vorhanden.

Möglicherweise stellen Sie fest, dass ich anstelle von json().datajson().results habe. Das liegt daran, dass der Server laut Tutorial mit einem Objekt geantwortet hat, das ein data-Feld hat, mein eigener Server jedoch mit einem Objekt antwortet, das ein results-Feld hat. Wenn Sie das Tutorial ein wenig nach unten scrollen, wird dieser Punkt angezeigt.

Beachten Sie die Form der Daten, die der Server zurückgibt. Diese besondere Im-Memory-Web-API-Beispiel gibt ein Objekt mit einer Dateneigenschaft zurück. Ihre Die API gibt möglicherweise etwas anderes zurück. Passen Sie den Code an Ihr Web an API.

Um das zu korrigieren, habe ich so etwas versucht

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

Als ich das tat, wurde die .json () - Methode behoben, aber ein anderer Fehler tauchte auf 

Eigenschaftsergebnisse sind beim Typ Promise nicht vorhanden

Ich habe versucht, das zu beheben, indem ich eine Schnittstelle definiere

interface OrderResponse {
    orders: Order[];
}

Und den Get-Anruf an modifiziert 

 .get<OrderResponse>(url)...

Das hat aber auch nicht funktioniert. Ein weiterer Fehler ist aufgetreten

Der Typ 'OrderResponse' kann nicht dem Typ 'Response' zugeordnet werden.

Ein Hinweis ist, dass im Tutorial das Angular HttpModule verwendet wurde. In meiner Anwendung verwende ich jedoch das neue Angular HttpClientModule. Vielleicht kommt also der Fehler.

Ich bin neu bei Angular 2 und dies ist die erste App, die ich damit baue. Wenn der obige Code mit dem neuen HttpClientModule nicht mehr gültig ist, würde ich mich über eine Hilfestellung freuen, wie Sie dies mit dem neuen HttpClientModule erreichen können. 

Ich habe ähnliche Fragen gefunden Die Eigenschaft 'json' existiert nicht für den Typ '{}' und Die Eigenschaft ist für den Typ 'object' nicht vorhanden , aber keine der Antworten dort hat mir geholfen. 

Update

Wie aus den Kommentaren hervorgeht, gibt es im neuen HttpClientModule keine .json () - Methode. Ich wäre immer noch dankbar, wenn ich mit dem neuen Modul den gleichen Effekt erzielen könnte. Vom Guide aus haben sie so etwas gemacht

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

Was ich perfekt verstehe, aber mein Problem ist, dass sich Code nicht in einer Komponente befindet, sondern in einem Dienst, der das Aufrufen von subscribe und das Zuweisen des Ergebnisses zu einem Instanzfeld nicht sinnvoll macht. 

Ich brauche meinen Service, um eine Reihe von Bestellungen in einem Versprechen zurückzusenden. Die meine Komponenten können einfach telefonieren wie

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

Ich habe auch daran gedacht, eine lokale Variable in meiner Service-Abrufmethode zu deklarieren, damit ich dies tun kann

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

Aber das macht für mich nicht viel Sinn, da der Aufruf von .get () asynchron ist und die Methode möglicherweise zurückkehrt, sogar bevor alle Daten abgerufen werden und das order-Array leer ist.

Update

Wie hier angefordert, ist der Code für handleError

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

UPDATE: für rxjs> v5.5

Wie in einigen Kommentaren und anderen Antworten erwähnt, deserialisiert der HttpClient den Inhalt einer Antwort standardmäßig in ein Objekt. Bei einigen seiner Methoden kann ein generisches Typargument übergeben werden, um das Ergebnis einzugeben. Deshalb gibt es keine json()-Methode mehr.

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))
    );
} 

Beachten Sie, dass Sie die zurückgegebene Observable leicht in eine Promise umwandeln können, indem Sie einfach toPromise() aufrufen.

ORIGINAL ANTWORT:

In Ihrem Fall können Sie 

Angenommen, Ihr Backend gibt so etwas zurück:

{results: [{},{}]}

im JSON-Format, wo jedes {} ein serialisiertes Objekt ist, benötigen Sie Folgendes:

// 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 ([])
  }
} 

Ich habe den catch-Abschnitt entfernt, da dieser über einen HTTP-Interceptor archiviert werden konnte. Überprüfen Sie die Dokumente . Zum Beispiel: 

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

Und um zu konsumieren, musst du es nur so nennen:

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

Für zukünftige Besucher: In der neuen HttpClient (Angular 4.3+) ist das response-Objekt standardmäßig JSON, sodass Sie response.json().data nicht mehr ausführen müssen. Verwenden Sie einfach response direkt.

Beispiel (geändert aus der offiziellen Dokumentation):

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));
  }
}

Vergessen Sie nicht, es zu importieren und das Modul unter Importe in das app.module.ts Ihres Projekts aufzunehmen:

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

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

Für zukünftige Besucher: Im neuen HttpClient (Angular 4.3+) ist das Antwortobjekt standardmäßig JSON, sodass Sie keine response.json (). -Daten mehr benötigen. Nutzen Sie einfach direkt die Antwort.

0