创建绑定到现有函数的 Observable
Creating an Observable that binds to an existing function
我一直在尝试将 ng2-file-upload
包中的 onCompleteItem
数组函数绑定到我可以订阅的 RxJS Observable 方法。
这里是我正在谈论的功能:
onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any;
..在使用中几乎与相同:
onCompleteItem(item: any, response: any, status: any, headers: any)
这是来自 MyComponent 的相关部分,目前正在运行:
imageArray: Image[] = [];
uploader:FileUploader = new FileUploader({
url: '/api/FileUpload'
});
ngOnInit() {
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
const data = JSON.parse(response);
data.forEach(x => {
console.log(x);
this.imageArray.push(x);
}
this.uploader.removeFromQueue(item);
};
}
我试图通过使用 RxJS bindCallback
函数将其绑定到 Observable 中:
bindCallback(this.uploader.onCompleteItem, {item: any, response: any, status: any, headers: any})().pipe(
tap((item, response) => {
const data = JSON.parse(response);
this.uploader.removeFromQueue(item);
const images = data.map(x => console.log(x) );
this.imageArray.push(...images);
})
).subscribe();
这行不通,因为有一些 type/syntax 错误。有没有人对如何将其重写为绑定的 Observable 函数有什么好的建议?
bindCallback
包装了一个函数,该函数在订阅可观察对象时调用,例如getJSON(url, callback)
。您正试图通过传递 callback
参数来使用它。
相反,您可以尝试 fromEventPattern
函数,它允许您通过其两个参数指定如何注册事件处理程序,以及如何取消注册。
const {fromEventPattern} = rxjs;
const uploader = {
upload() {
setTimeout(() => {
if (this.onCompleteItem) this.onCompleteItem('arg 1', 'arg 2');
}, 1000);
}
};
const source = fromEventPattern(handler => uploader.onCompleteItem = handler, _ => uploader.onCompleteItem = null);
source.subscribe(([arg1, arg2]) => console.log(arg1, arg2));
uploader.upload();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.js"></script>
这是一次真正的旅程..但我希望这个答案能给一些用户带来新的见解。
这里有一些我最初采用的有效解决方案,列出的最后一个解决方案是我最终实施的。
初步解:
const obs = new Observable<{ item: FileItem, response: string }>(sub => {
this.uploader.onCompleteItem = (item: FileItem, response: string) => sub.next({ item, response });
return () => this.uploader.onCompleteItem = undefined;
});
bindCallback((x: (item: FileItem, response: string) => any) => this.uploader.onCompleteItem = x)()
.pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
})
).subscribe();
上述解决方案的唯一问题是 bindCallBack
只触发一次。
更完善的解决方案:
Observable.create((sub: Subscriber<[FileItem, string]>) => {
this.uploader.onCompleteItem = (item: FileItem, response: string) => sub.next([item, response]);
return () => this.uploader.onCompleteItem = undefined;
}).pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
})
).subscribe();
这让我开始思考。我考虑过使用 fromEvent
,因为它订阅了 jQuery 操作和浏览器事件,但除非编写了包装器,否则不会。这就是导致我使用 fromEventPattern
:
的最终解决方案的原因
最终解决方案:(完整代码)
ngOnInit() {
fromEventPattern<Parameters<FileUploader['onCompleteItem']>>(x => this.uploader.onCompleteItem = x).pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
this.imageArray = this.imagesSubject.getValue();
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
// because I'm using a Subject
this.imagesSubject.next(this.imageArray);
})
).subscribe();
}
ngOnDestroy() {
this.onDestroySubj.next();
}
我一直在尝试将 ng2-file-upload
包中的 onCompleteItem
数组函数绑定到我可以订阅的 RxJS Observable 方法。
这里是我正在谈论的功能:
onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any;
..在使用中几乎与相同:
onCompleteItem(item: any, response: any, status: any, headers: any)
这是来自 MyComponent 的相关部分,目前正在运行:
imageArray: Image[] = [];
uploader:FileUploader = new FileUploader({
url: '/api/FileUpload'
});
ngOnInit() {
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
const data = JSON.parse(response);
data.forEach(x => {
console.log(x);
this.imageArray.push(x);
}
this.uploader.removeFromQueue(item);
};
}
我试图通过使用 RxJS bindCallback
函数将其绑定到 Observable 中:
bindCallback(this.uploader.onCompleteItem, {item: any, response: any, status: any, headers: any})().pipe(
tap((item, response) => {
const data = JSON.parse(response);
this.uploader.removeFromQueue(item);
const images = data.map(x => console.log(x) );
this.imageArray.push(...images);
})
).subscribe();
这行不通,因为有一些 type/syntax 错误。有没有人对如何将其重写为绑定的 Observable 函数有什么好的建议?
bindCallback
包装了一个函数,该函数在订阅可观察对象时调用,例如getJSON(url, callback)
。您正试图通过传递 callback
参数来使用它。
相反,您可以尝试 fromEventPattern
函数,它允许您通过其两个参数指定如何注册事件处理程序,以及如何取消注册。
const {fromEventPattern} = rxjs;
const uploader = {
upload() {
setTimeout(() => {
if (this.onCompleteItem) this.onCompleteItem('arg 1', 'arg 2');
}, 1000);
}
};
const source = fromEventPattern(handler => uploader.onCompleteItem = handler, _ => uploader.onCompleteItem = null);
source.subscribe(([arg1, arg2]) => console.log(arg1, arg2));
uploader.upload();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.js"></script>
这是一次真正的旅程..但我希望这个答案能给一些用户带来新的见解。
这里有一些我最初采用的有效解决方案,列出的最后一个解决方案是我最终实施的。
初步解:
const obs = new Observable<{ item: FileItem, response: string }>(sub => {
this.uploader.onCompleteItem = (item: FileItem, response: string) => sub.next({ item, response });
return () => this.uploader.onCompleteItem = undefined;
});
bindCallback((x: (item: FileItem, response: string) => any) => this.uploader.onCompleteItem = x)()
.pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
})
).subscribe();
上述解决方案的唯一问题是 bindCallBack
只触发一次。
更完善的解决方案:
Observable.create((sub: Subscriber<[FileItem, string]>) => {
this.uploader.onCompleteItem = (item: FileItem, response: string) => sub.next([item, response]);
return () => this.uploader.onCompleteItem = undefined;
}).pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
})
).subscribe();
这让我开始思考。我考虑过使用 fromEvent
,因为它订阅了 jQuery 操作和浏览器事件,但除非编写了包装器,否则不会。这就是导致我使用 fromEventPattern
:
最终解决方案:(完整代码)
ngOnInit() {
fromEventPattern<Parameters<FileUploader['onCompleteItem']>>(x => this.uploader.onCompleteItem = x).pipe(
takeUntil(this.onDestroySubj),
tap(([item, response]) => {
this.imageArray = this.imagesSubject.getValue();
const data = JSON.parse(response);
this.imageArray.push(...data );
this.uploader.removeFromQueue(item);
// because I'm using a Subject
this.imagesSubject.next(this.imageArray);
})
).subscribe();
}
ngOnDestroy() {
this.onDestroySubj.next();
}