更改 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
我的应用程序具有以下内容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