布局之间的角度变化检测需要重新加载

问题描述 投票:0回答:1

我被要求在不破坏任何逻辑的情况下更新项目的 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;
    });
    }

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

我尝试过:

  1. 使用 ChangeDetectionRef 进行手动更改检测。 detectorChanges 和 markForCheck 都被使用了。
  2. HeaderComponent 中的 NgZone.run()。在其中运行订阅逻辑以反映更改。
  3. HeaderComponent 中的Applicatoin.ref()
  4. 在AfterViewInit、OnInit、NgDoCheck中编写了相同的订阅逻辑。没有任何效果。
  5. 没有 ChangeDetectionStrategy 未在父组件中的任何位置设置为 OnPush。

在尝试和测试代码后,我发现当我将

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

angular layout data-binding storage angular2-changedetection
1个回答
0
投票

我会把它设置得更像 - 使用主题创建全局状态管理。

// 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;
})
© www.soinside.com 2019 - 2024. All rights reserved.