将解析器与保护功能一起使用时,无法使用嵌套的可观察对象进行解析

时间:2019-04-09 21:03:11

标签: angular typescript nested observable resolver

我有一个角度离子应用程序,可以从API检索文章。这些文章可以是免费的,也可以是需要活跃会员资格的高级文章。我正在使用解析器来确保文章存在,然后再继续进行路由。在该解析器中,我还尝试检查是否存在登录用户,以及该用户是否处于活动状态。使用日志记录似乎一切正常,但是如果有登录的活动用户,则不会加载路由。我认为这与我错误地嵌套/映射可观察对象有关。

在我的AppUserService上,我将用户身份(表示用户已登录)设置为BehaviorSubject,以便我可以对其进行订阅。

import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';

import { IdentityInterface } from './../models/identity.interface'
/**
 * AppUserService is used app-wide to identify the current user of the app
 * This only related to any user modules or services that would be for
 * communicating with the API about user data insofar as the identity set
 * on this service should from data obtained by an external service for authenticating
 * and getting a user
 */
@Injectable({
    providedIn: 'root'
})
export class AppUserService {
    /**
     *
     */
    private identity = new BehaviorSubject<IdentityInterface>(null);
    public identity$ = this.identity.asObservable();

    private returnUrl: any = ["/home"];

    constructor() {
    }

    /**
     * "Logs" the user in which is essentially setting their identity
     */
    public login(identity: IdentityInterface){
        this.setIdentity(identity);
    }

    /**
     * "Logs" the user out which essentially just removes identity information from storage
     */
    public logOut(){
        this.setIdentity(null);
    }

    /**
     * Sets the identity member property and saves to storage
     */
    public setIdentity(identity): void{
        // --- Broadcast the setting of the identity on the identity subject so other
        // --- parts of the app subscribed to this can pick up on it
        this.identity.next(identity);
        this.saveIdentityToStorage(identity);
    }

    /**
     * Attempts to automatically log in a user based on identity data in localstorage
     */
    public attemptAutoLogin(){
        let identity = this.getIdentityFromStorage();
        if(identity !== null){
            this.login(identity);
        }
    }

    /**
     * Returns the URL the user should be sent to after successful login
     */
    public getReturnUrl(defaultUrl: any = null){
        return this.returnUrl;
    }

    /**
     * Returns the URL the user should be sent to after successful login
     */
    public setReturnUrl(url: any){
        this.returnUrl = url;
    }

    /**
     * Uses local storage to save identity data
     */
    private saveIdentityToStorage(identity){
        localStorage.setItem("identity", JSON.stringify(identity));
    }

    /**
     * Loads identity data from storage
     */
    private getIdentityFromStorage(){
        return JSON.parse(localStorage.getItem("identity"));
    }
}

在解析器中,我使用ArticleService从API中获取响应,如果找到了响应并且该响应不是免费的,则尝试订阅AppUserService身份以查看是否存在登录用户。这些都按预期工作

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable, of, EMPTY }  from 'rxjs';
import { map, switchMap, take }         from 'rxjs/operators';

import { AppUserService } from './../../../core/services/app-user.service';

import { Article } from './../models/article';
import { ArticleService } from './../services/article.service';
import { User } from './../../user/models/user';

/**
 * Make sure we have the Article data before loading the Article view page
 */
@Injectable({
  providedIn: 'root'
})
export class ArticleResolverService implements Resolve<Article> {

    constructor(
        private articleService: ArticleService,
        private appUserService: AppUserService,
        private router: Router
    ) {}

    resolve(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ): Observable<Article> | Observable<never> {
        // --- Load the article from the API
        return this.articleService.read(parseInt(route.paramMap.get("id"))).pipe(
            take(1),
            switchMap(article => {
                if (article) {
                    console.log("article found");
                    // --- If it's not free do some auth checks
                    if(!article.free){
                        console.log("article is premium");
                        return this.appUserService.identity$.pipe(
                            map( result => {
                                let user = (!result ? null : result as User);
                                // -- If no user identity is set send them to login
                                if(!user){
                                    console.log("no user");
                                    this.appUserService.setReturnUrl([state.url]); // --- Router requires array
                                    this.router.navigate(['/user/login']);
                                    return EMPTY;
                                } else if(!user.active){
                                    console.log("user not active");
                                    this.router.navigate(['/subscribe']);
                                    return EMPTY;
                                } else {
                                    console.log("user is active");
                                    console.log(article);
                                    return of(article);
                                }
                            })
                        );
                    } else {
                        console.log("article is free");
                        return of(article);
                    }
                } else { // id not found
                    console.log("article not found");
                    this.router.navigate(['/article/list']);
                    return EMPTY;
                }
            })
        );
    }
}

当我尝试访问免费文章时,无论是否登录,它都能按预期工作。当我尝试访问高级文章时,如果没有用户或非活动用户,它将按预期转发我。但是,当有活动的登录用户时,它不会加载路由。它仅与文章页面未加载在同一页面上。这是我尝试的控制台日志记录。将文章对象记录到控制台后,它返回文章的可观察结果,但未按照预期的路线前进:


core.js:16829 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
common.js:290 Native: tried calling StatusBar.styleDefault, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator
common.js:290 Native: tried calling SplashScreen.hide, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator
article-resolver.service.ts:35 article found
article-resolver.service.ts:60 article is free
core.js:11462 WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss
article-resolver.service.ts:35 article found
article-resolver.service.ts:38 article is premium
article-resolver.service.ts:44 no user
article-resolver.service.ts:35 article found
article-resolver.service.ts:38 article is premium
article-resolver.service.ts:53 user is active
article-resolver.service.ts:54 
Article {id: 3854, category_id: 107, format_id: 101, title: "Offseason Dynasty Refocus: TE", author: "Matt Schauf", …}
article-resolver.service.ts:35 article found
article-resolver.service.ts:60 article is free
core.js:11462 WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss
article-resolver.service.ts:35 article found
article-resolver.service.ts:38 article is premium
article-resolver.service.ts:53 user is active
article-resolver.service.ts:54 
Article {id: 3844, category_id: 107, format_id: 101, title: "Offseason Dynasty Refocus: Quarterback", author: "Matt Schauf", …}

我假设这里的问题是不知道如何正确地“折叠”可观察对象,并确保它正确地从嵌套的可观察对象中返回(文章)。我读了很多文章,但无法弄清楚。这是我使用的两个相关链接:

https://blog.angular-university.io/rxjs-higher-order-mapping/

Angular2: Nested Observables in Guard

0 个答案:

没有答案