我被要求在不 destruct 任何逻辑的情况下更新项目的UI(我 destruct 了). 在旧的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中的订阅逻辑运行良好(user不是null),但是当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;
    });
    }

刷新后,它工作正常,但它不应该这样工作,是吗?

我试过:

  1. 使用ChangeDetectionRef手动变更检测.detectChanges和markForCheck都使用了.
  2. 在HeaderComponent中使用NgZone.run().在其中运行订阅逻辑以关联更改.
  3. HeaderComponent中的Applicationatoin. ref()
  4. 在AfterViewInit、OnInit、NgDoCheck中编写了相同的订阅逻辑.什么都没有用.
  5. No ChangeDetectionStrategy在父组件中的任何地方都不会设置为OnPush.

在try 和测试代码之后,我发现当我将HeaderComponent移到AuthLayoutComponent的子部分(或者只是将其粘贴在AuthLayoutComponent中)时,它在使用相同的打字脚本时没有任何问题.从这里,我确定问题是由于在路由配置中使用了不同的布局和子属性.我知道这个问题,但我不知道如何在保留新UI的同时解决它. 有谁知道为什么ChangeDetection不工作而不刷新页面时,使用不同的布局?(服务是共享的,因此它们应该检测到更改).

我try 将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;
})

Angular相关问答推荐

无法绑定到ngIf,因为它不是dis angular 17的已知属性

Angular 17自定义指令渲染不起作用'

Angular 类型的表单不能分配给分部类型

将sass与@Use语句一起使用时出现Angular 新的VITE构建器编译错误

如何从URL中角下载图片?

ANGLING:ExpressionChangedAfterChecked在嵌套形式中由子项添加验证器

Angular 组件存储,为什么我的效果可以';在http错误后不会被触发?

Angular将文件作为字符串读取给dxf解析器

如何将 Angular 中的导航路由到同一页面并重新加载

Angular 不使用NgRx的简单CRUD应用程序

IonicStorageModule似乎不是 NgModule 类

如何在 Angular14 中创建带有验证的自定义输入组件?

如何更改 Angular material 按钮中的内部 RippleColor 和 UnboundedRipple 效果?

如何以Angular 2 获取当前路由自定义数据?

Angular 4 - 在下拉列表中 Select 默认值 [Reactive Forms]

如何在angular material中使用输入类型文件

EmptyError: no elements in sequence

在 Angular 中动态设置样式

Angular 2中不同页面的多种布局

无法绑定到 target,因为它不是div的已知属性