我有一个角度离子应用程序,可以从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/