javascript - Cancelar una solicitud HTTP pendiente y activar fromEvent nuevamente en Angular 6 y Rxjs 6
Puedo cancelar la solicitud HTTP pendiente (usando .unsubscribe), pero después de esto no activará mi fromEvent(this.searchInput.nativeElement, 'keyup'). ¿Cómo lo manejo?
Estoy usando "fromEvent(this.searchInput.nativeElement, 'keyup')" para obtener resultados de búsqueda. Pero si hay una solicitud HTTP pendiente y el usuario borra el campo, quiero cancelar la solicitud (intenté unsubscribe y funciona). Pero, después de eso, el 'fromEvent' no se dispara. ¿Alguna idea de cómo manejarlo?
fromEvent(this.searchInput.nativeElement, 'keyup')
.pipe(
map((event: any) => {
if (event.keyCode === 17 || event.keyCode === 91 || event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40 || event.keyCode === 13 || event.keyCode === 27) {
return;
}
return event.target.value;
}),
filter((query: any) => {
if (query === '') {
this.loading = false;
this.searchedResult = [];
}
return query && query.length > 0;
}),
debounceTime(300)
,distinctUntilChanged((p, c) => {
return !!this.searchedResult && this.searchedResult.length > 0 && (p == c);
})
, switchMap(query => {
query = query.trim();
this.loading = true;
return this.cartService.searchItemByName(encodeURIComponent(query), this.shopID.shop_id.toString()).pipe(
catchError(err => {
this.toaster.error(err.error.message || "Something went wrong!");
return of([]); //in case of error let’s emit an empty array
})
);
})
).subscribe((res: any) => {
let data = res.result;
this.loading = false;
this.searchedResult = data;
if (data && data.length) this.setSelectedItem(data[0], 0)
})
Respuesta #1
SwitchMap ya cancela la suscripción si llega un nuevo término de búsqueda. Así que eliminaría los efectos secundarios de tu código y manejaría el caso de término vacío no con un filtro sino con un retorno condicional.
fromEvent(document.getElementById('source'), 'keyup')
.pipe(
map((event: any) => event.target.value),
debounceTime(300),
switchMap(query => {
const trimmed = query.trim();
this.loading = true;
return trimmed === '' ? of([]) : fakeHttp(query);
})
)
.subscribe((res: any) => {
this.loading = false;
console.log(res);
});
En acción: https://stackblitz.com/edit/rxjs-tg4gew?devtoolsheight=60
Respuesta #2
takeUntil podría hacer el trabajo aquí:
searchInputEvent = new Subject();
fromEvent(this.searchInput.nativeElement, 'keyup')
.pipe(
tap(() => this.searchInputEvent.next()),
map((event: any) => {
if (event.keyCode === 17 || event.keyCode === 91 || event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40 || event.keyCode === 13 || event.keyCode === 27) {
return;
}
return event.target.value;
}),
filter((query: any) => {
if (query === '') {
this.loading = false;
this.searchedResult = [];
}
return query && query.length > 0;
}),
debounceTime(300)
,distinctUntilChanged((p, c) => {
return !!this.searchedResult && this.searchedResult.length > 0 && (p == c);
})
, switchMap(query => {
query = query.trim();
this.loading = true;
return this.cartService.searchItemByName(encodeURIComponent(query), this.shopID.shop_id.toString()).pipe(
takeUntil(this.searchInputEvent),
catchError(err => {
this.toaster.error(err.error.message || "Something went wrong!");
return of([]); //in case of error let’s emit an empty array
})
);
})
).subscribe((res: any) => {
let data = res.result;
this.loading = false;
this.searchedResult = data;
if (data && data.length) this.setSelectedItem(data[0], 0)
})Se va a anular la suscripción del observable searchItemByName previamente suscrito cada vez que se active el evento keyup. Puedes considerar que la solicitud debe cancelarse tan pronto como el usuario escriba, o solo cuando el tiempo de debounce haya terminado. En ese caso, coloca el tap después del debounceTime.
