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().data
json().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);
}
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[]
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,
...
],
...
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.