2017-02-21 6 views
1

У меня есть приложение, в котором для выхода из системы пользователя я должен удалять конечную точку REST. В моем угловом 2 фронтэнда, у меня есть следующие услуги, которые обрабатывает это:Вызов `next` из rxjs` Subject` отменяет http-вызов

@Injectable() 
export class AuthService { 

    private authEvents: Subject<boolean>; 

    constructor(private http: Http) { 
    this.authEvents = new Subject<boolean>(); 
    } 

    login(email: string, password: string): Observable<Response> { 
    const url = 'rest/auth/login'; 
    const body = { 
     email: email, 
     password: password 
    }; 
    return this.http.post(url, body) 
     .do((res: Response) => { 
     localStorage.setItem('currentUser', JSON.stringify(res.json())); 
     this.authEvents.next(true); 
     }); 
    } 

    logout(): Observable<Response> { 
    const url = 'rest/auth/logout'; 
    return this.http.post(url, {}) 
     .do((res: Response) => { 
     localStorage.removeItem('currentUser'); 
     console.log('hereee!'); 
     this.authEvents.next(false); 
     }); 
    } 

    isSignedIn(): boolean { 
    return localStorage.getItem('currentUser') !== null; 
    } 

    get events(): Observable<boolean> { 
    return this.authEvents; 
    } 

} 

Позвольте мне объяснить, что я пытаюсь сделать здесь. У меня есть authEvents предмет, который я подписаться на мой компонент, как так:

ngOnInit() { 
    this.isSignedIn = this.authService.isSignedIn(); 
    this.authService.events.subscribe(() => { 
    this.isSignedIn = this.authService.isSignedIn(); 
    }); 
} 

Когда пользователь нажимает кнопку выхода из системы, я вызвать следующую функцию в этом компоненте:

logout() { 
    this.authService.logout() 
    .subscribe(() => { 
     this.router.navigate(['/home']); 
    }, e => this.handleError(e)); 
} 

Проблема заключается в том, что переадресация браузера на дом, даже если вызов для выхода еще не завершен. Так эффективно, иногда интерфейс успешно выходит из системы, а иногда и нет! Что я здесь делаю неправильно?

Примечание: сеанс на бэкэнд всегда выходит из системы, так как HTTP-вызов действительно происходит. Я также хотел бы посмотреть, как использовать Observables (и rxjs в целом) для достижения этого, хотя, если слишком много проблем, то Promises могут быть использованы.

+0

Осторожно, используя .do(), как и для побочных эффектов и отладки в основном. Кроме того, я старался избегать горячих наблюдателей, когда это было возможно. Они могут сделать отладку вашего приложения немного сложнее. – DarkNeuron

ответ

0

Вот что работал me:

Как я уже сказал, я изменил свой Subject на BehaviorSubject.

Но то, что казалось неправильным, было фактически в html компонента.

<li routerLinkActive="active"><a href="#" (click)="logout(); $event.preventDefault()">Logout</a></li> 

мне пришлось добавить на $event.preventDefault() вызов в (click) события и все, кажется, работает, как ожидалось. Хотя, если кто-нибудь может объяснить мне, почему это так, было бы здорово!

+2

Это из-за 'href =" # "' <- удалить это, и вам не понадобится 'preventDefault' - это приведет к тому, что приложение перейдет к« корню », что мешает маршрутизатору углов – olsn

+0

@olsn, который сделал Это. –

2

С Subject у вас есть случай, что выбросы принимаются только подписчиками, а не будущими подписчиками. Я предполагаю, что это ваша проблема здесь - чтобы облегчить вашу жизнь, вы можете использовать BehaviorSubject, который повторно передает текущее значение любому будущему абоненту, так что вам не нужно беспокоиться о каких- условия.

Однако: Строго видно не будет событие больше, но больше государства, которое является тем, что я хотел бы предложить использовать в любом случае в вашем случае - так как с RxJS вы можете использовать мощь государств над событиями ,

@Injectable() 
export class AuthService { 

    public currentUser$: BehaviorSubject<IUser> = new BehaviorSubject(null); // initial state is "null" => user is not logged in 
    private isSignedIn$: Observable<boolean> = currentUser$.map(user => Boolean(user)).share(); 

    constructor(private http: Http) { 
    this.authEvents = new Subject<boolean>(); 
    } 

    login(email: string, password: string): Observable<Response> { 
    const url = 'rest/auth/login'; 
    const body = { 
     email: email, 
     password: password 
    }; 
    return this.http.post(url, body) 
     .do((res: Response) => { 
     localStorage.setItem('currentUser', JSON.stringify(res.json())); 
     this.currentUser$.next(res.json()); // will automatically trigger the logged-in state as well 
     }); 
    } 

    logout(): Observable<Response> { 
    const url = 'rest/auth/logout'; 
    return this.http.post(url, {}) 
     .do((res: Response) => { 
     localStorage.removeItem('currentUser'); 
     console.log('hereee!'); 
     this.currentUser$.next(null); // will automatically trigger the logged-in state as well 
     }); 
    } 
} 

В компоненте

private desotryed$: Subject<boolean> = new Subject(); 

ngOnInit() { 
    this.authService.isSignedIn$ 
    .takeUntil(this.desotryed$) // to prevent memory leaks through a perpetual subscription 
    .subscribe(isSignedIn => { 
     this.isSignedIn = isSignedIn; 
    }); 
} 

ngOnDestroy() { 
    this.desotryed$.next(true); 
} 

Поскольку документы RxJS5 не включая в BehaviorSubject еще, вот ссылка на старые документы: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md

+0

Это будет работать, я верю (спасибо!), Но я пошел с другим подходом, который я опубликовал в качестве ответа. Добавление «$ event.preventDefault()» с вызовом logout(), похоже, работает. Можете ли вы сказать мне, почему это работает? –

 Смежные вопросы

  • Нет связанных вопросов^_^