J'essaie de map
à partir d'un appel de service mais j'obtiens une erreur . Regardé/ subscribe n'est pas défini dans l'angle 2? et il est dit que pour souscrire, nous devons revenir de l'intérieur des opérateurs. J'ai aussi des déclarations de retour.
Voici mon code:
checkLogin(): Observable<boolean> {
return this.service.getData()
.map(
response => {
this.data = response;
this.checkservice = true;
return true;
},
error => {
// debugger;
this.router.navigate(['newpage']);
console.log(error);
return false;
}
)
.catch(e => {
return e;
});
}
Journal d'erreur:
TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
Dans votre exemple de code, votre opérateur map
reçoit deux rappels, alors qu'il ne devrait en recevoir qu'un. Vous pouvez déplacer votre code de traitement des erreurs vers votre rappel de capture.
checkLogin():Observable<boolean>{
return this.service.getData()
.map(response => {
this.data = response;
this.checkservice=true;
return true;
})
.catch(error => {
this.router.navigate(['newpage']);
console.log(error);
return Observable.throw(error);
})
}
Vous devez également importer les opérateurs catch
et throw
.
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
EDIT: Notez qu'en renvoyant Observable.throw
dans votre gestionnaire catch, vous ne capturez pas réellement l'erreur - elle restera visible sur la console.
Dans mon cas, l'erreur s'est produite uniquement lors des tests e2e. Cela est dû à throwError
dans mon AuthenticationInterceptor.
Je l'ai importé à partir d'une source incorrecte car j'ai utilisé la fonctionnalité d'importation de WebStorm. J'utilise RxJS 6.2.
Faux:
import { throwError } from 'rjxs/internal/observable/throwError';
Correct:
import { throwError } from 'rjxs';
Voici le code complet de l'intercepteur:
import { Injectable } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const reqWithCredentials = req.clone({withCredentials: true});
return next.handle(reqWithCredentials)
.pipe(
catchError(error => {
if (error.status === 401 || error.status === 403) {
// handle error
}
return throwError(error);
})
);
}
}
Vous retournez un observable alors que votre code ne renvoie qu'un booléen. Donc, vous devez utiliser comme ci-dessous
.map(response => <boolean>response.json())
Si vous utilisez un autre service commun checkservice
dans votre cas, vous pouvez simplement utiliser
this.service.getData().subscribe(data=>console.log(data));
Cela rendra votre fonction checkLogin()
avec le type de retour nulle.
checkLogin():void{
this.service.getData()
.map(response => {
this.data = response;
this.checkservice=true;
}).subscribe(data=>{ });
et vous pouvez utiliser this.checkService
pour vérifier votre condition
Si votre fonction s'attend à renvoyer un booléen, procédez comme suit:
import { Observable } from 'rxjs/Observable';
checkLogin(): Observable<boolean>{
return this.service.getData()
.map(response => {
this.data = response;
this.checkservice=true;
return true;
})
.catch(error => {
this.router.navigate(['newpage']);
console.log(error);
return Observable.of(false);
})
}
J'oubliais de rendre l'autre observable dans pipe(switchMap(
this.dataService.getPerson(personId).pipe(
switchMap(person => {
//this.dataService.getCompany(person.companyId); // return missing
return this.dataService.getCompany(person.companyId);
})
)
J'ai été confronté à ce problème lors de la tentative d'authentification d'un utilisateur à l'aide d'un jeton Web JSON. dans mon cas, c'est lié à l'intercepteur d'authentification.
L'envoi d'une demande d'authentification d'un utilisateur ne nécessite pas de jeton puisqu'il n'existe pas encore.
Vérifiez que votre intercepteur inclut ceci:
if (req.headers.get('No-Auth') == "True")
return next.handle(req.clone());
Et que vous fournissiez {'No-Auth':'True'}
à votre requête d'en-tête comme ceci:
authenticateUser(user): Observable<any> {
const headers = new HttpHeaders({'No-Auth':'True'});
headers.append('Content-Type', 'application/json');
return this.httpClient.post(`${this.apiEndpoint}/auth/authenticate`, user, {headers: headers});
}
,
) dans un RxJS pipe(...)
La compilation n'acceptera pas cette virgule supplémentaire à la fin:
pipe(first(), map(result => ({ event: 'completed', result: result}),);
Cela devient un opérateur 'invisible' undefined
qui visse tout le tuyau et conduit à un message d'erreur très déroutant - qui dans ce cas n'a rien à voir avec ma logique réelle.
J'ai écrit ceci parce que j'arrive ici en cherchant la même erreur et que cela pourrait être utile pour quelqu'un à l'avenir.
Je reçois la même erreur en essayant d'initialiser une variable de service à partir de son constructeur en appelant une API distante via http.get et . Subscribe ()
Après de nombreux tests sans comprendre le problème, je l’ai enfin compris: mon application avait une authentification et un HttpInterceptor, et j’essayais d’initialiser le service en appelant une méthode API publique à l’aide de http. get (...) sans 'No-Auth' en-têtes. Je les ai ajoutés comme ici, et le problème résolu pour moi:
getData() {
var reqHeader = new HttpHeaders({ 'Content-Type': 'application/x-www-urlencoded','No-Auth':'True' });
return this.http.get(environment.urlApi.Literales, { headers: reqHeader });
}
Quel mal de tête :(
Dans mon cas dans Angular-5, le fichier de service n’était pas importé et j’accédais à la méthode et abonnais les données. Après l’importation du fichier de service, cela fonctionnait parfaitement.
J'ai le même message d'erreur exact pendant que je faisais mon test d'unité et que je levais une exception observable après me moquer de mes services.
Je l'ai résolu en passant la fonction exacte et le format dans Observable.throw
.
Code actuel qui appelle le service et subscribe
pour obtenir des données. remarquez que catch
permet de gérer l’erreur 400
.
this.search(event).catch((e: Response) => {
if (e.status === 400) {
console.log(e.json().message);
} else if (e.url) {
console.log('HTTP Error: ' + e.status + ' ' + e.statusText,
'URL: ' + e.url, 'Info: ' + e.json().message));
}
}).finally(() => {
this.loading = false;
}).subscribe((bData) => {
this.data = bData;
});
Le code à l'intérieur du service
search() {
return this.someService.getData(request)
.do((r) => {
this.someService.defaultHeaders.delete('skipAlert');
return r;
})
.map((r) => {
return r.businessObjectDataElements.length && r.businessObjectDataElements || null;
});
}
Je me suis moqué de SomeService et ai renvoyé des données observables et tout est bien car il contient toutes les méthodes requises.
someServiceApi = fixture.debugElement.injector.get(SomeService);
spyOn(someServiceApi, 'getData').and.returnValue(Observable.of({}));
Le code ci-dessus est correct, mais lorsque je tentais de tester la condition d'erreur/capture en passant Observable.throw({})
, il me montrait l'erreur car il attendait le retour du type Response
.
Donc, en dessous du service, le retour moqueur me donnait cette erreur.
someServiceApi.getData
.and.returnValue(Observable.throw(new Response({status: 400, body: [], message: 'not found error'})));
Donc, je l'ai corrigé en répliquant la fonction exacte attendue dans mon objet de retour, en passant plutôt une valeur de type Response
.
someServiceApi.getData
.and.returnValue(Observable.throw({status: 400, json: () => { return {message: 'not found error'}}, body: []}));
// see `json: () => { return {message: 'not found error'}}` inside return value