1

我的应用程序具有以下内容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.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(顺便说一句,我知道这个名字很糟糕)。

这是ProductContainerproduct-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();

4

2 回答 2

1

首先,我想建议将所有逻辑从 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

于 2020-06-23T22:54:43.433 回答
0

尝试在您的 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;
        });

我希望这有效

于 2020-06-23T22:29:55.833 回答