更改 URL 时未触发主题

Subject not being triggered when changing URL

我的应用程序具有以下内容app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { PageNotFoundComponent } from './core/page-not-found/page-not-found.component';

const routes: Routes = [
  { path:  '', redirectTo: 'forms', pathMatch: 'full'  },
  { path:  'forms', loadChildren : () => import('./pages/forms/forms.module').then(m => m.FormsModule)   },
  { path:  'admin', loadChildren : () => import('./pages/admin/admin.module').then(m => m.AdminModule)   },
  { path: '**', component: PageNotFoundComponent }  

@NgModule({
   imports: [RouterModule.forRoot(routes)],
   exports: [RouterModule]
}) 
export class AppRoutingModule { }

如您所见,我有两个我称之为“产品”的东西,它们是“表单”和“管理”,它们分别由 url /forms 和 /admin 访问。

app.component.html如下:

<navbar></navbar>

<div class="container">
  <ngx-spinner
    bdColor = "rgba(51, 51, 51, 0.6)"
    size = "large"
    color = "white"
    type = "ball-running-dots">

  <p style="font-size: 20px; color: white">Loading...</p>

  </ngx-spinner>

  <router-outlet></router-outlet>
</div>

<app-footer></app-footer>

如您所见,我有组件“navbar”,标记为 <navbar></navbar>。问题是,这个导航栏的内容会根据用户所在的产品而有所不同。为了让事情更清楚,让我们看看 navbar.component.html:

<default-navbar *ngIf="currentProduct == 'forms'"></default-navbar>
<div *ngIf="currentProduct != 'forms'">
    lalalallala
</div>

还有 navbar.component.ts:

import { OnInit, OnDestroy, Component } from '@angular/core';
import { Subscription } from '../../../../../node_modules/rxjs';
import { ProductEnum } from '../../../shared/models/enums/product-enum';
import { ProductContainer } from '../../../shared/containers/product-container';

@Component({
    selector: 'navbar',
    templateUrl: './navbar.component.html',
    styleUrls: ['./navbar.component.scss']
  })
export class NavbarComponent implements OnInit, OnDestroy 
{
    public currentProduct:ProductEnum;

    private subscription = Subscription.EMPTY;

    constructor(private _productContainer:ProductContainer) 
    {
        
    }

    ngOnInit(): void 
    {
        this.currentProduct = this._productContainer.getCurrentProduct();
        this.initializeSubscribers();
    }

    ngOnDestroy(): void 
    {
        this.subscription.unsubscribe();
    }

    private initializeSubscribers():void
    {
        this.subscription.add(this._productContainer.getChangeCurrentProductSubject().subscribe(_newCurrentProduct => {
            this.currentProduct = _newCurrentProduct;
        }));
    }
}

因此导航栏内容会因 currentProduct 属性 而异。这个变量将由存在于我称为 ProductContainer 的可注入服务上的主题 属性 更新(顺便说一下,我知道这个名字很糟糕)。

这里是 ProductContainer(product-container.ts) 代码:

import { Injectable } from '@angular/core';
import { Subject } from '../../../../node_modules/rxjs';
import { ProductEnum } from '../models/enums/product-enum';

@Injectable({
    providedIn: 'root',
  })
export class ProductContainer
{
    private changeCurrentProductSubject: Subject<ProductEnum> = new Subject<ProductEnum>();

    private currentProduct: ProductEnum = ProductEnum.Forms;
    
    public setCurrentProduct(_newCurrentProduct:ProductEnum):void
    {
        this.currentProduct = _newCurrentProduct;
        this.changeCurrentProductSubject.next(this.currentProduct);
    }

    public getCurrentProduct():ProductEnum
    {
        return this.currentProduct;
    }

    public getChangeCurrentProductSubject():Subject<ProductEnum>
    {
        return this.changeCurrentProductSubject;
    }
}

所以如果我们回到 app-routing.module.ts,我们可以看到当访问 \admin url 时,AdminModule 被加载。这是 AdminModule 代码:

import { CommonModule } from '@angular/common';
import { SharedModule } from '../../shared/shared.module';
import { NgModule } from '@angular/core';
import { AdminRoutingModule } from './admin-routing.module';
import { AdminHomeModule } from './admin-home/admin-home.module';
import { CoreModule } from '../../core/core.module';
import { ProductContainer } from '../../shared/containers/product-container';
import { ProductEnum } from '../../shared/models/enums/product-enum';
import { Router, RouterModule } from '@angular/router';

@NgModule({
    declarations: [],
    imports: [
      CommonModule,
      SharedModule,
      AdminRoutingModule,
      AdminHomeModule,
      CoreModule,
      RouterModule
    ]
})
export class AdminModule
{
  constructor(private _productContainer:ProductContainer, private router: Router)
  {  
    this._productContainer.setCurrentProduct(ProductEnum.Admin);
  }
}

因此,当访问 \admin url 时,它会将当前产品设置为 Admin,因此导航栏会知道该产品已更新。

但是问题很简单,导航栏里面的订阅没有被触发。

(编辑:部分错误也是由使用 private subscription = Subscription.EMPTY; 引起的,当我替换为 private subscription = new Subscription(); 时它说工作)

尝试在您的 product.container.ts 文件中使用此函数,

public getChangeCurrentProductSubject(): Observable<ProductEnum>
{
    return this.changeCurrentProductSubject.asObservable();
}

这在您的 navbar.component.ts 文件中

ngOnInit(): void 
{
    this.initializeSubscribers();
    this.currentProduct = this._productContainer.getCurrentProduct();
}

另外,尝试像这样修改 navbar.component.ts 文件中的订阅

import { Subscription } from "rxjs";
private subscription = Subscription;

this.subscription = this._productContainer.getChangeCurrentProductSubject().subscribe(_newCurrentProduct => {
         this.currentProduct = _newCurrentProduct;
        });

我希望这有效

首先,我想建议从 NgModule 中移走所有逻辑,这是不好的做法,为此模块不存在。

我不明白您想如何在 AdminModule 的构造函数中更改 currentProduct?这个不行,第一次下载后模块将不再加载,所以构造函数将不会被调用。

您可以订阅 url 更改事件。在导航栏组件中:

      if (this.router.url.startsWith(`/forms`)) {
               this.currentProduct = ProductEnum.Forms;
      } else if (this.router.url.startsWith(`/admin`)) {
               this.currentProduct ProductEnum.Admin;
      }

      this.router.events.subscribe(event => {
        if (event instanceof NavigationEnd) {
            if (event.url.startsWith(`/forms`)) {
               this.currentProduct = ProductEnum.Forms;
            } else if (event.url.startsWith(`/admin`)) {
               this.currentProduct = ProductEnum.Admin;
            }
        }
      })

但如果我是你,我会在导航栏中定义“页面类型”(管理或表单或其他)参数,并将此导航栏转移到模块的根页面,并为子页面创建一个出口(以免每个页面都添加导航栏)

以防万一使用 BehaviorSubject 而不是 Subject