Angular rxjs: сохранить подписку после достижения ошибки - PullRequest
1 голос
/ 18 июня 2019

Мне нужно знать, как сохранить подписку после выдачи ошибки.

Я создал это наблюдаемое:

let saveClick$ = Observable.fromEvent(this.saveButton.nativeElement, 'click');

Итак, я попытался с Observable.empty,но, насколько мне удалось выяснить, он испускает полный, поэтому подписчик будет удален:

this.saved$ = saveClick$.pipe(this.pushUser(), catchError(() => Observable.empty<AdministrationUser>()), share());

Я хочу, чтобы при достижении любой ошибки подписка сохранялась.

Есть идеи?

Дополнительный код:

// Custom pipes
private push = <T>() => switchMap<T, AdministrationUser>(() => this.service.push(this.user));
private handleError = <T>() => catchError<T, Array<{code: string, message: string}>>((error: ResponseError) => Observable.of(error.errors));
private handleEmptyUser = <T>() => catchError<T, AdministrationUser>(() => Observable.of(UsuarisadministracioSubcomponentComponent.EMPTY_USER));

private pushUser = () => pipe( //simplified pipe
    this.push()
);

И мой сервис:

const buildURL = () => map((filter: {userId: string} & Trace) => this.buildPushURL(filter.currentUser, filter.currentApplication, filter.userId));
const makeRequest = () => switchMap((url: string) => httpMethodFn.call(this.authHttp, url, user));
const buildResponse = () => map(() => user);
const onErrorGetDetails = () => catchError((error: Response) => Observable.throw(<ResponseError>error.json()));

return Observable.of({userId: user.id})
    .pipe(
        buildURL(),
        makeRequest(),
        buildResponse(),
        onErrorGetDetails()
    );

Ответы [ 2 ]

1 голос
/ 18 июня 2019

Вы должны отловить ошибку во внутреннем наблюдаемом конвейере вместо наблюдаемого источника. Если вы поймаете ошибку в источнике, наблюдаемом, то, согласно концепции rxjs, наблюдаемый источник не будет выдавать новые значения после возникновения ошибки. Так что лови ошибку во внутренней наблюдаемой так:

this.saved$ = saveClick$.pipe(
                               //i am assuming this.pushUser() is a higher order function which returns an observable
                               this.pushUser()
                                   .pipe(
                                          catchError(() => Observable.empty<AdministrationUser>())
                                        ),
                                        share()
                                    );

Поймав ошибку во внутренней наблюдаемой, ваш источник станет видимым живым и будет продолжать излучать значения, даже если ваша внутренняя наблюдаемая выдает ошибку. Вы можете перемещать своего share() оператора в соответствии с вашими потребностями [т.е. либо внутри вашей внутренней наблюдаемой, либо в наблюдаемой линии трубопровода источника], но идея остается той же - поймайте ошибку внутри внутренней наблюдаемой трубы, чтобы сохранить ваш источник (внешний) наблюдаемый живым.

РЕДАКТИРОВАТЬ 1: [Предлагая упрощенный код в соответствии с последним кодом пользователя]

Пожалуйста, определите ваш метод push в вашем сервисе так:

push(user) {

    //By seeing your code; I could not figure out where and how are you passing the parameter in buildUrl
    //It appears to me that this.buildPushURL method simply return an URL based on the passed parameters and IT DOES NOT MAKE
    //ANY HTTP CALL TO YOUR BACKEND. IF THAT IS TRUE - 
    //THEN please adjust the below code accordingly as I dont know how you use this method OR PLEASE provide some more detaling 
    //on  this.buildPushURL() method
    const url = this.buildPushURL(filter.currentUser, filter.currentApplication, filter.userId);

    //I am assuming that httpMethodFn calls http.get() or http.post() and returns an observable
    //Suggestion - Why you dont use httpClient.get or httpClient.post() directly? It will avoid to call
    //httpMethodFn by httpMethodFn.call?

    //Bottom line is - httpMethodFn.call must return an observable otherwise adjust your httpMethodFn.call code to return an observable
    //to make below code work.
    return httpMethodFn.call(this.authHttp, url, user)
                       .pipe(
                           map(user => {
                               console.log(user);
                               return user;
                           }),
                           catchError(error => throwError(<ResponseError>error.json()))
                       );

}

И используйте это так -

yourMethodReturnsAnObservableWhichIsSubscribeByTheConsumer() {

    const saveClick$ = Observable.fromEvent(this.saveButton.nativeElement, 'click');

    return saveClick$.pipe(

            switchMap(() => {
                return this.push(user)
                            .pipe(
                                //you catch error here so that your outer observable will keep alive

                                //please adjust you code as per your need
                                //I guess it will give you an idea
                                handleError()
                            )
            })


    );
}

Надеюсь, вы получите представление о том, как упростить ваш код. Я не мог предоставить идеальное решение, так как я не знаю о вашем дизайне и полном коде. Я уверен, что приведенный выше код даст вам представление.

Предложение. Хорошо использовать функцию высшего порядка, но следует понимать, что не следует злоупотреблять ими, поскольку это затрудняет понимание вашего кода [PS - Это мое личное мнение, и хорошо иметь разные мнения. . :)]. Сделайте свою наблюдаемую цепочку максимально простой, применяя функциональный стиль кодирования. RXJS - это круто :)

0 голосов
/ 18 июня 2019

Вам нужно использовать оператор catchError и возвращать НИКОГДА наблюдаемый

 import { NEVER } from 'rxjs';
 import { catchError } from 'rxjs/operators';

 observable$.pipe(catchError((error: any) => {return NEVER;}));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...