我正在构建一个配置文件页面,并试图让经过身份验证的用户数据显示在那里。我的API调用与他们的id一起工作,如果我手动将id输入到url中,它在前端工作。
但是当我尝试从导航栏导航到配置文件时,我收到了
400 Bad Request for URL: http://localhost:3000/users/undefined
我现在可以假设它是一个异步问题。我的个人资料页面调用用户数据,但该用户数据在我的导航组件中不可用。如果我想正确导航,似乎我需要将我的id param传入我的个人资料[routerLink]。由于我的用户数据在我的导航组件中不可用,因此无法通过。
有更好的方法吗?我应该使用事件发射器吗?
Angular的新手 - 非常感谢!
import { Component, OnInit, Input } from '@angular/core';
import { AuthService } from '.././services/auth.service';
import { UserService } from '.././services/user.service'
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css'],
providers: [UserService]
})
export class ProfileComponent implements OnInit {
currentUser;
isAuth: boolean;
constructor(
private session: AuthService,
private router: Router,
private userService: UserService,
private route: ActivatedRoute
) {
this.session.isAuth
.subscribe((isAuth: boolean) => {
// user will be false if logged out
// or user object if logged in.
this.isAuth = isAuth;
});
if (this.session.token) {
this.isAuth = true;
console.log(this.session);
} else {
this.isAuth = false;
}
}
ngOnInit() {
this.route.params.subscribe(params => {
this.getUserDetails(params['id']);
});
}
getUserDetails(id) {
this.userService.get(id)
.subscribe((user) => {
this.currentUser = user;
console.log(this.currentUser);
});
}
}
我正在导航到我的个人资料页面。
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">bnb</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li *ngIf="!isAuth"><a [routerLink]="['login']">Login</a></li>
<li *ngIf="isAuth"><a [routerLink]="['profile']"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profile</a></li>
<li *ngIf="isAuth"><a (click)="logout()">Logout</a></li>
<li *ngIf="!isAuth"><a [routerLink]="['signup']">Signup</a></li>
</ul>
</div>
</div>
</nav>
import { Component, OnInit, Input } from '@angular/core';
import { AuthService } from '.././services/auth.service';
import { UserService } from '.././services/user.service';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
isAuth: boolean;
currentUser: any;
constructor(
private session: AuthService,
private userService: UserService,
private router: Router,
private route: ActivatedRoute
) {
this.currentUser = JSON.parse(localStorage.getItem("User"))
console.log("USER",this.currentUser) //Currently returns Null
console.log(this.session)
this.session.isAuth
.subscribe((isAuth: boolean) => {
// user will be false if logged out
// or user object if logged in.
this.isAuth = isAuth;
});
if (this.session.token) {
this.isAuth = true;
} else {
this.isAuth = false;
}
}
ngOnInit() {
}
logout() {
this.session.logout();
}
}
import { Routes } from '@angular/router';
import { LoginComponent } from '../login/login.component';
import { SignupComponent } from '../signup/signup.component';
import { HomeComponent } from '../home/home.component';
import { RentalListingsComponent } from '../rental-listings/rental-listings.component';
import { SingleRentalComponent } from '../rental-listings/single-rental/single-rental.component';
import { ProfileComponent } from '../profile/profile.component'
import { AuthService } from '../services/auth.service';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: 'rentals', component: RentalListingsComponent },
{ path: 'listing', component: SingleRentalComponent },
{ path: 'profile/:id', component: ProfileComponent, canActivate: [AuthService] } <--profile path. I know I have to match my url paths, but don't know how to do this from the navbar.
// { path: 'home', component: HomeComponent, canActivate: [AuthService] },
{ path: '**', redirectTo: '' }
];
答案 0 :(得分:1)
感谢您提供详细信息。在某个地方,您需要订阅“登录后”或“身份验证”事件,获取用户配置文件JSON,并将其保存到localstorage,以便您可以在任何地方使用它。如果您无法挂钩或订阅其中一个,那么请在代码中方便的地方执行。找出您可以进行哪些调用以获取整个用户JSON并将其保存如下...
查看下面的AuthService init()。第一行是this.authProvider.on('authenticated', this.onAuth);
。无论您使用何种身份验证服务API,都应该为您提供一种方法,以便在有人登录时指定回调(提供登录令牌)。onAuth
回调函数将令牌保存在localstorage中,然后fetchProfile(...){...}
生成另一个调用身份验证服务API以使用刚刚收到的令牌this.user.getProfile(idToken, this.onProfile);
获取整个JSON用户配置文件。例如,我在项目中使用Auth0,而我对Auth0 API的调用看起来像this.lock.getProfile(idToken, this.onProfile);
,但我将其替换为您的调用可能类似的示例this.user.getProfile(idToken, this.onProfile);
因此,请使用您在API中使用的任何内容替换fetchProfile 。然后onProfile
回调使用this.localStorage.set('profile', profile);
将整个JSON配置文件保存在本地存储中的单个密钥中。然后,您可以通过调用this.localStorage.get('profile')
随时获取它。
app.module.ts
...
@NgModule({
imports: [
...
UserService,
...
]
providers: [
...
UserService,
...
]
auth.service.ts
@Injectable()
export class Auth {
userProfile: UserProfile;
constructor(
...
private localStorage: LocalStorageService,
private router: Router,
private user: UserService,
private authProvider: ...
...
) {
}
init() {
this.authProvider.on('authenticated', this.onAuth);
// Set userProfile attribute if already saved profile
this.userProfile = this.localStorage.get('profile');
setTimeout(() => { // let AppComponent listener initialize
this.localStorage.set('profile', this.userProfile);
}, 0);
}
}
onAuth = (authResult: AuthResult) => {
this.localStorage.set('id_token', authResult.idToken);
this.fetchProfile(authResult.idToken);
}
// Save current route for redirect url
login() {
this.localStorage.set('redirect_url', this.router.url);
this.authProvider.show({initialScreen: 'login'});
};
// Check if user is logged in.
authenticated() {
// Check if unexpired token.
// Searches for item in localStorage with key == 'id_token'
return this.authProvider.tokenNotExpired();
};
logout() {
this.router.navigateByUrl('');
this.userProfile = undefined; // do before localstorage
this.localStorage.remove('id_token');
this.localStorage.remove('profile');
};
fetchProfile(idToken: string) {
this.user.getProfile(idToken, this.onProfile);
}
/**
* On profile event callback.
* Save profile to LocalStorage.
* Redirect to url if present in LocalStorage.
*/
onProfile = (error: any, profile: UserProfile) => {
if (error) {
console.log(error);
return;
}
this.userProfile = profile;
this.localStorage.set('profile', profile);
// Redirect if there is a saved url to do so.
const redirectUrl: string = this.localStorage.get('redirect_url');
if (redirectUrl !== undefined) {
this.router.navigateByUrl(redirectUrl);
this.localStorage.remove('redirect_url');
}
}
localstorage.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class LocalStorageService {
[key:string]: any;
/**
* define your localstorage variables here as observables
*/
id_token$ = new Subject();
redirect_url$ = new Subject();
profile$ = new Subject();
customer$ = new Subject();
set(key: string, value: any) {
this[key + '$'].next(value); // this will make sure to tell every subscriber about the change.
localStorage.setItem(key, JSON.stringify(value));
}
get(key: string) {
const value = localStorage.getItem(key);
return value && JSON.parse(value);
}
remove(key: string) {
this[key + '$'].next(undefined);
localStorage.removeItem(key);
}
}
app.component.ts
export class AppComponent implements OnDestroy, OnInit {
webRobot: boolean = false;
private profileSub: any;
private customerSub: any;
private subscriptionSub: any;
constructor(
private analyticsService: AnalyticsService,
private auth: Auth,
private localStorage: LocalStorageService,
) {
}
ngOnInit(): void {
this.init();
}
init() {
this.auth.init(this.webRobot);
this.analytics.init(this.webRobot);
if (!this.webRobot) {
// subscribe to authed profile changes
this.profileSub =
this.localStorage.profile$.subscribe(this.onProfile);
// Subscribe to changes to Stripe customer
this.customerSub =
this.localStorage.customer$.subscribe(this.onCustomer);
}
// always delete active subscribes on destroy
ngOnDestroy() {
this.profileSub.unsubscribe();
this.customerSub.unsubscribe();
}
onProfile = (profile: UserProfile) => {
// ...do stuff
}
onCustomer= (profile: Customer) => {
// ...do stuff
}
答案 1 :(得分:0)
在您的个人资料路由配置中,它需要id
查询参数
{ path: 'profile/:id', component: ProfileComponent, canActivate: [AuthService] }
<--profile path.
I know I have to match my url paths,
but don't know how to do this from the navbar.
但您的导航栏链接未传递ID值
<li *ngIf="isAuth"><a [routerLink]="['profile']"><span class="glyphic
你需要在导航栏中做这样的事情
<li *ngIf="isAuth"><a [routerLink]="['profile/user.id']">