Rxjs 嵌套观察者未执行
Rxjs Nested observer is not executed
我已经阅读了很多关于如何在 RxJs 和 Angular 中嵌套观察者的文档、文章和不同的线程,但我仍然遗漏了一些东西并且最终无法得到结果。
这是我的代码:
page.ts
export class LiabilitiesPage implements OnInit {
constructor(
private liabilityService: LiabilityService,
private router: Router
) {}
refreshLiabilities() {
// Get the liabilities
console.log('refreshing') // passing there
this.liabilityService.getAllLiabilities().subscribe(
(response: Liability[]) => {
console.log(response); // <=== Never pass there !
if (response) {
this.liabilities = response;
} else {
// empty response code
}
}, error => {
// response error code (never passing there either)
}
}
}
liability.service.ts
// all the needed imports
@Injectable({
providedIn: 'root'
})
export class LiabilityService {
constructor(
private authService: AuthService,
private http: HttpClient,
) {}
// first try : Do not send the http request
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions()
.pipe(
tap(options => this.http.get<Liability[]>(this.url + 'me/', options))
);
}
// try 2 : Doesn't work either
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions()
.pipe(
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options)), // at this point I tried pretty much every operators (map, mergeMap etc.)
withLatestFrom()
);
}
/* this code was working before that I transformed the authService.getOptions in observable (it was just returning the options synchronyously before)
getAllLiabilities(): Observable<Liability[]> {
return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());
}*/
}
auth.service.ts
public getOptions(): Observable<any> {
return new Observable((observer) => {
this.storage.get('authToken').then((token) => {
console.log('passing') // Pass here
if (token && typeof token.auth_token !== 'undefined') {
console.log('passing') // pass here as well
this.isLoggedIn = true;
this.token = token.auth_token;
}
// it is returning the value
return {
headers: this.headers.set('Authorization', 'Bearer ' + this.token),
params: new HttpParams()
};
})
});
}
我尝试了几乎所有可能的运算符组合以使其在 liabilityService 中工作但没有成功。
问题:
问题是我的 page.ts
订阅了 this.http.get<Liability[]>(this.url + 'me/', options)
观察者,但是 none xhr 请求被触发了。 http get 观察器从未执行过,我不明白我在那里遗漏了什么。
我刚刚开始试验 Angular,但如果我理解正确的话,操作员应该进行映射和展平,但这看起来永远不会发生。
奖金问题:
我也不明白为什么初始代码:
return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());
正在返回 Observable<Liability[]>
并使用 switchMap :
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))
它正在返回 Observable<HttpEvent<Liability[]>>
如果有人有线索并有时间回答我,那就太好了
你的promise回调有问题then()
:
this.storage.get('authToken').then((token) => {
return something; // this won't work.
})
您可以使用 from
,这将 convert
您对 observable 的承诺。
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
public getOptions(): Observable<any> {
return from(this.storage.get('authToken')).pipe(map(token => {
return headers with token.
}));
}
所以你可以像这样重写你的代码:
授权服务:
private token: string | null = null;
public getOptions(): Observable<any> {
return this.getToken().pipe(
map(token => {
return {
headers: this.headers.set('Authorization', 'Bearer ' + token),
params: new HttpParams()
};
})
);
}
private getToken(): Observable<string | null> {
if (this.token) {
return of(this.token);
}
return from(this.storage.get('authToken')).pipe(
map(token => token?.authToken || null),
tap(token => this.token = token)
);
}
那么你可以使用switchmap:
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions().pipe(
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))
);
}
更新
获得 HttpEvent<T>
的原因是因为当 .get()
的重载接收到 any
object 时,http 事件处理完全由您决定。
如果你想让它 return 提供的元素类型,你必须满足适当的重载。
你可以这样做:
而不是 return 整个选项,我们只 return headers,这应该足够了,因为我们真的没有足够的东西来谈论其余的选项。
授权服务
private token: string | null = null;
public createTokenHeaders(): Observable<HttpHeaders> {
const headers = new HttpHeaders();
return addToken(headers);
}
public addToken(headers: HttpHeaders): Observable<HttpHeaders> {
return this.getToken().pipe(
map(token => headers.set('Authorization', 'Bearer ' + (token || '')))
);
}
private getToken(): Observable<string | null> {
if (this.token) {
return of(this.token);
}
return from(this.storage.get('authToken')).pipe(
map(token => token?.authToken || null),
tap(token => this.token = token)
);
}
然后像这样使用它:
getAllLiabilities(): Observable<Liability[]> {
const url = this.url + 'me/';
const headers = new HttpHeaders();
return this.authService.addToken(headers).pipe(
switchMap(updatedHeaders => this.http.get<Liability[]>(url, { headers: updatedHeaders }))
);
}
或:
getAllLiabilities(): Observable<Liability[]> {
const url = this.url + 'me/';
return this.authService.createTokenHeaders().pipe(
switchMap(headers => this.http.get<Liability[]>(url, { headers }))
);
}
注意:确保使用从调用 addToken 得到的 headers returned。重复使用您自己的实例化 headers
将不起作用,因为设置 header 总是 return 一个新的 HttpHeaders
object。它是不可变的。
我已经阅读了很多关于如何在 RxJs 和 Angular 中嵌套观察者的文档、文章和不同的线程,但我仍然遗漏了一些东西并且最终无法得到结果。
这是我的代码:
page.ts
export class LiabilitiesPage implements OnInit {
constructor(
private liabilityService: LiabilityService,
private router: Router
) {}
refreshLiabilities() {
// Get the liabilities
console.log('refreshing') // passing there
this.liabilityService.getAllLiabilities().subscribe(
(response: Liability[]) => {
console.log(response); // <=== Never pass there !
if (response) {
this.liabilities = response;
} else {
// empty response code
}
}, error => {
// response error code (never passing there either)
}
}
}
liability.service.ts
// all the needed imports
@Injectable({
providedIn: 'root'
})
export class LiabilityService {
constructor(
private authService: AuthService,
private http: HttpClient,
) {}
// first try : Do not send the http request
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions()
.pipe(
tap(options => this.http.get<Liability[]>(this.url + 'me/', options))
);
}
// try 2 : Doesn't work either
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions()
.pipe(
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options)), // at this point I tried pretty much every operators (map, mergeMap etc.)
withLatestFrom()
);
}
/* this code was working before that I transformed the authService.getOptions in observable (it was just returning the options synchronyously before)
getAllLiabilities(): Observable<Liability[]> {
return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());
}*/
}
auth.service.ts
public getOptions(): Observable<any> {
return new Observable((observer) => {
this.storage.get('authToken').then((token) => {
console.log('passing') // Pass here
if (token && typeof token.auth_token !== 'undefined') {
console.log('passing') // pass here as well
this.isLoggedIn = true;
this.token = token.auth_token;
}
// it is returning the value
return {
headers: this.headers.set('Authorization', 'Bearer ' + this.token),
params: new HttpParams()
};
})
});
}
我尝试了几乎所有可能的运算符组合以使其在 liabilityService 中工作但没有成功。
问题:
问题是我的 page.ts
订阅了 this.http.get<Liability[]>(this.url + 'me/', options)
观察者,但是 none xhr 请求被触发了。 http get 观察器从未执行过,我不明白我在那里遗漏了什么。
我刚刚开始试验 Angular,但如果我理解正确的话,操作员应该进行映射和展平,但这看起来永远不会发生。
奖金问题:
我也不明白为什么初始代码:
return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());
正在返回 Observable<Liability[]>
并使用 switchMap :
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))
它正在返回 Observable<HttpEvent<Liability[]>>
如果有人有线索并有时间回答我,那就太好了
你的promise回调有问题then()
:
this.storage.get('authToken').then((token) => {
return something; // this won't work.
})
您可以使用 from
,这将 convert
您对 observable 的承诺。
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
public getOptions(): Observable<any> {
return from(this.storage.get('authToken')).pipe(map(token => {
return headers with token.
}));
}
所以你可以像这样重写你的代码:
授权服务:
private token: string | null = null;
public getOptions(): Observable<any> {
return this.getToken().pipe(
map(token => {
return {
headers: this.headers.set('Authorization', 'Bearer ' + token),
params: new HttpParams()
};
})
);
}
private getToken(): Observable<string | null> {
if (this.token) {
return of(this.token);
}
return from(this.storage.get('authToken')).pipe(
map(token => token?.authToken || null),
tap(token => this.token = token)
);
}
那么你可以使用switchmap:
getAllLiabilities(): Observable<Liability[]> {
return this.authService.getOptions().pipe(
switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))
);
}
更新
获得 HttpEvent<T>
的原因是因为当 .get()
的重载接收到 any
object 时,http 事件处理完全由您决定。
如果你想让它 return 提供的元素类型,你必须满足适当的重载。
你可以这样做:
而不是 return 整个选项,我们只 return headers,这应该足够了,因为我们真的没有足够的东西来谈论其余的选项。
授权服务
private token: string | null = null;
public createTokenHeaders(): Observable<HttpHeaders> {
const headers = new HttpHeaders();
return addToken(headers);
}
public addToken(headers: HttpHeaders): Observable<HttpHeaders> {
return this.getToken().pipe(
map(token => headers.set('Authorization', 'Bearer ' + (token || '')))
);
}
private getToken(): Observable<string | null> {
if (this.token) {
return of(this.token);
}
return from(this.storage.get('authToken')).pipe(
map(token => token?.authToken || null),
tap(token => this.token = token)
);
}
然后像这样使用它:
getAllLiabilities(): Observable<Liability[]> {
const url = this.url + 'me/';
const headers = new HttpHeaders();
return this.authService.addToken(headers).pipe(
switchMap(updatedHeaders => this.http.get<Liability[]>(url, { headers: updatedHeaders }))
);
}
或:
getAllLiabilities(): Observable<Liability[]> {
const url = this.url + 'me/';
return this.authService.createTokenHeaders().pipe(
switchMap(headers => this.http.get<Liability[]>(url, { headers }))
);
}
注意:确保使用从调用 addToken 得到的 headers returned。重复使用您自己的实例化 headers
将不起作用,因为设置 header 总是 return 一个新的 HttpHeaders
object。它是不可变的。