我使用Angular http和RXJS来检索一些应用程序设置。 http使用RXJS shareReplay来避免多个相同的调用。
这按预期工作,并且检查“网络”选项卡,我只能看到对后端API的一次调用。
我的应用程序中的某些组件将调用该服务,并使用结果来呈现页面。其他组件则需要像上面那样调用该服务,但是然后再次对结果执行“某些操作”,例如,更多的http调用,然后呈现页面。当尝试稍后时,我得到类型错误:
Argument of type '(result: any) => void' is not assignable to parameter of type '(value: any, index: number)' => ObservableInput<{}>
在我的switchMap上使用。
-不带switchMap的简单示例----
cart.component.ts
ngOnInit() {
this.systemPreferences.getPreferences()
.subscribe(
(result: any) => {
this.headerTitle = result.title || '';
},
(err) => {
console.log('there has been an error');
},
() => // Some completion code
);
}
systemPreferences.service.ts:
const CACHE_SIZE = 1;
export class SystemPreferences {
private $cache: Observable<Object>
private requestConfig() {
return this.http.get("/api/some/endpoint").pipe(
map(response => response.value)
);
}
public getPreferences() {
if (!this.cache$) {
this.cache$ = this.requestConfig().pipe(
shareReplay(CACHE_SIZE)
);
}
return this.cache$;
}
}
/api/some/endpoint示例响应:
{
"appName": "Tables Forks and Spoons",
"title": "My title",
"regionUrls": [
"http://www.region1.com:8021",
"http://www.region2.com:8021",
"http://www.region3.com:8021",
"http://www.region4.com:8021"
],
"nonRegionUrls": [
"http://www.non-region1.com:8021",
"http://www.non-region2.com:8021",
"http://www.non-region3.com:8021",
"http://www.non-region4.com:8021"
]
}
-类型错误的简单示例,例如switchMap ----
cart.component.ts
ngOnInit() {
this.systemPreferences.getPreferences()
.pipe(
.switchMap((result: any) => {
this.systemPreferences.getLiveUrl(result['regionUrls']);
}))
.subscribe(
(result: any) => {
this.liveLink = result.liveLink; // result.livelink is added as part of this.systemPreferences.getLiveUrl above
this.headerTitle = result.title || '';
},
(err) => {
console.log('there has been an error');
}
);
}
systemPreferences.service.ts:
const CACHE_SIZE = 1;
export class SystemPreferences {
private $cache: Observable<Object>
private requestConfig() {
return this.http.get("/api/some/endpoint").pipe(
map(response => response.value)
);
}
public getPreferences() {
if (!this.cache$) {
this.cache$ = this.requestConfig().pipe(
shareReplay(CACHE_SIZE)
);
}
return this.cache$;
}
public getLiveUrl(urls: any) {
let promises = [];
urls.forEach((url) => {
promises.push(this.http.get(url + 'some/endpoint/'));
});
const results = forkJoin(promises) {
.subscribe((data: any) => {
return this.getBest(data);
}
}
}
public getBest(data: any) {
// Loops through data, and returns a single URL as a string
// 'http//www.thebesturltouse.com'
}
}
更新:
尝试返回建议的第二个observable(见下文),具有与上面相同的类型void错误。
cart.component.ts
ngOnInit() {
this.systemPreferences.getPreferences()
.pipe(
.switchMap((result: any) => {
return this.systemPreferences.getLiveUrl(result['regionUrls']);
}))
.subscribe(
(result: any) => {
this.liveLink = result.liveLink; // result.livelink is added as part of this.systemPreferences.getLiveUrl above
this.headerTitle = result.title || '';
},
(err) => {
console.log('there has been an error');
}
);
}
systemPreferences.service.ts:
const CACHE_SIZE = 1;
export class SystemPreferences {
private $cache: Observable<Object>
private $switchObs: Observable<Object>
private requestConfig() {
return this.http.get("/api/some/endpoint").pipe(
map(response => response.value)
);
}
public getPreferences() {
if (!this.cache$) {
this.cache$ = this.requestConfig().pipe(
shareReplay(CACHE_SIZE)
);
}
return this.cache$;
}
public getLiveUrl(urls: any) {
let promises = [];
urls.forEach((url) => {
promises.push(this.http.get(url + 'some/endpoint/'));
});
const results = forkJoin(promises) {
.subscribe((data: any) => {
this.$switchObs = this.getBest(data);
return this.$switchObs;
}
}
}
public getBest(data: any) {
// Loops through data, and returns a single URL as a string
// 'http//www.thebesturltouse.com'
}
}
更新到多个switchMap
cart.component.ts
ngOnInit() {
this.systemPreferences.getPreferences()
.pipe(
.switchMap((result: any) => {
return this.systemPreferences.getLiveUrl(result['regionUrls']);
}),
.switchMap((liveRegion: any) => {
return this.systemPreferences.getBest(liveRegion);
}))
.subscribe(
(bestUrl: String) => {
console.log('best');
console.log(bestUrl);
},
(err) => {
console.log('there has been an error');
}
);
}
systemPreferences.service.ts:
const CACHE_SIZE = 1;
export class SystemPreferences {
private $cache: Observable<Object>
private $switchObs: Observable<String>
private requestConfig() {
return this.http.get("/api/some/endpoint").pipe(
map(response => response.value)
);
}
public getPreferences() {
if (!this.cache$) {
this.cache$ = this.requestConfig().pipe(
shareReplay(CACHE_SIZE)
);
}
return this.cache$;
}
public getLiveUrl(urls: any) {
let promises = [];
urls.forEach((url) => {
promises.push(this.http.get(url + 'some/endpoint/'));
});
return forkJoin(promises);
}
public getBest(data: any) {
// Loops through data, and returns a single URL as a string
//
return this.$switchObs; // = 'http//www.thebesturltouse.com'
}
}
有了以上内容,在console.log('best')/console.log(bestUrl)上,我看到了:
'best'
h
'best'
t
'best'
t
'best'
p
'best'
:
'best'
/
'best'
/
'best'
w
'best'
w
'best'
w
'best'
.
'best'
b
etc etc etc
不仅仅是字符串http//www.thebesturltouse.com
更新。
在multi switchMap示例中,如果我返回Obserbable.of(this。$ switchObs);我得到了预期的单字符串URL。
这感觉不是解决此问题的最佳方法。
最佳答案
该问题与switchMap
运算符本身无关。事实是,您的getLiveUrl
方法的类型为void。 switchMap需要一个返回observable的函数作为输入参数。因此,您希望getLiveUrl
返回一个可观察值。为了实现这一点,代码可能看起来像这样(请注意,我不是100%不确定getBest
实际在做什么,这可能会影响解决方案。):
public getLiveUrl(urls: any) {
let promises = [];
urls.forEach((url) => {
promises.push(this.http.get(url + 'some/endpoint/'));
});
return forkJoin(promises).pipe(
map(data => this.getBest(data))
);
}
我仍然不能100%地确定您实际要实现的目标,但我希望这对您有所帮助。
关于angular - switchMap类型void无法分配给ObservableInput <{}>类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53628962/