我被要求在不破坏任何逻辑的情况下更新项目的 UI(我破坏了)。 在旧的 UI 身份验证(登录页面)和其余部分(身份验证后访问的其他资源)具有相同的布局(页眉 + 内容 + 页脚),但在新的身份验证页面中,其布局与应用程序不同布局(登录后)。 所以我以这种方式分离布局:
RouterModule.forRoot([
{ path: 'auth', component: AuthLayoutComponent,
children: [
{ path: '', component: AuthHomeComponent },
{ path: 'login', component: LoginComponent},
{ path: 'terms-of-use', component: TermsOfUseComponent},
{ path: 'contact', component: AuthContactFormComponent}
]
},
{ path: '', component: HomeComponent,
children: [
{ path: 'contact', component: ContactFormComponent },...]
bootstrap: [AppComponent]
HomeComponent
是应用程序的布局,而AuthLayoutComponent
是认证部分的布局。
旧配置:
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'contact', component: ContactFormComponent },
...]
bootstrap: [AppComponent]
新
AppComponent
:
<ng-container>
<router-outlet></router-outlet>
<sac-alert></sac-alert>
<sac-loader></sac-loader>
</ng-container>
老
AppComponent
:
<app-header></app-header>
<div class="body-content">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
新
HomeComponent
:
<div class="admin-container">
<app-navigation></app-navigation>
<div class="admin-section-container">
<app-header></app-header>
<main>
<ng-container>
<router-outlet></router-outlet>
</ng-container>
</main>
</div>
</div>
一切都按预期进行,直到我注意到
HeaderComponent
在登录后不显示登录用户的姓名,而在旧版本中它会立即出现在右上角。
HeaderComponent
:
<div ngbDropdown class="d-inline-block dropdown" *ngIf="isLoggedIn && user">
<button type="button" class="btn" ngbDropdownToggle id="userDropdown">
<img src="assets/icons/combo shape.svg" alt=""> <span *ngIf="user.surname">{{user.surname}}</span>
<span *ngIf="user.name">{{user.name}}</span>
</button>
HeaderComponent.ts
:
constructor(
private apiService: ApiService,
public entityMapService: EntityMapService,
public changeNotificationsService: ChangeNotificationsService,
public router: Router,
public cdr: ChangeDetectorRef
) {
this.isProduction = environment.production === true;
this.apiService.currentUserChanged.subscribe(user => {
this.user = user;
this.isLoggedIn = this.user != null;
});
}
currentUserChanged
中ApiService
:
public currentUser: UserInfo;
private currentUserChangeObservers: Observer<UserInfo>[] = [];
public currentUserChanged = new Observable<UserInfo>(observer => {
this.currentUserChangeObservers.push(observer);
});
UserInfo
只是一个界面。
现在正如我在旧版本中所说,一旦您登录,您的名字就会出现在
HeaderComponent
的右上角,但是在将 HeaderComponent
移动到不同的布局而不更改任何打字稿代码后,它不会显示用户名和姓氏,无需重新加载页面(f5)。因此,登录后我需要刷新页面才能发生更改。
使用 console.log 我看到 HeaderComponent 中的订阅逻辑运行良好(用户不为空),但是当 ngOnInit 中的 console.log(this.user)
时,我注意到它给出了 null
。
但是在
HeaderComponent
的构造函数中:
this.apiService.currentUserChanged.subscribe(user => {
this.user = user;
console.log(this.user)//gives actual object
this.isLoggedIn = this.user != null;
});
}
刷新后工作正常,但不应该这样工作,是吗?
我尝试过:
在尝试和测试代码后,我发现当我将
HeaderComponent
移动到 AuthLayoutComponent
的子部分(或者只是将其粘贴到 AuthLayoutComponent
中)时,它可以使用相同的打字稿正常工作。从这里我确定问题是由于在路线配置上使用不同的布局和子属性造成的。我知道这个问题,但我不知道如何在保留新用户界面的同时解决它。
任何人都知道为什么在使用不同布局时,如果不刷新页面,ChangeDetection 就无法工作?(服务是共享的,因此它们应该检测更改)。
我尝试将 RouteConfiguration 更改为此,但 ChangeDetection 仍然需要刷新页面:
const routes: Routes = [
{
path: '',
children: [
{
path: 'auth',
component: AuthLayoutComponent,
children: [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent },
{ path: 'terms-of-use', component: TermsOfUseComponent },
{ path: 'contact', component: AuthContactFormComponent }
]
},
{
path: 'home',
component: HomeComponent,
children: [
]
},
{ path: '', redirectTo: 'home', pathMatch: 'full' },
]
},
Angular 17.3.0,Zone.js 0.14.4
我会把它设置得更像 - 使用主题创建全局状态管理。
// ApiService file
@Injectable({providedIn: root})
export class ApiService {
// properties for the current user
private _currentUser$ = new ReplaySubject<User>(1);
public readonly currentUser$ = this._currentUser$.asObservable();
// a method that updates the currentUser, wherever this gets called ...
updateUserMethod(user: User) {
this._currentUsers$.next(user);
}
}
上面,设置为
providedIn: root
应该到处都可以使用。然后你可以在你的 HeaderComponent
构造函数中拥有:
this.apiService.currentUser$.subscribe(user => {
// do with the user what you need
this.user = user;
})