当改变URL时,主题不会被触发。

20 浏览
0 Comments

当改变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 { }

如您所见,我有两个我称之为“产品”的东西,它们分别是“forms”和“admin”,它们通过url /forms和/admin进行访问。

app.component.html如下所示:


  
  

Loading...

如您所见,我有一个组件“navbar”,被标记为。问题是,根据用户所在的产品,此导航栏的内容将有所不同。为了更清楚,让我们看一下navbar.component.html


    lalalallala

还有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的可注入服务上存在的subject属性进行更新(顺便说一句,这个名称很糟糕,我知道)。

以下是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 = new Subject();
    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
    {
        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,因此导航栏将知道产品已更新。

但问题很简单,navbar中的订阅不起作用。

(编辑:错误的一部分也是由于使用了private subscription = Subscription.EMPTY;,当我替换为private subscription = new Subscription();时它就开始工作了)

0
0 Comments

问题的出现原因:在navbar.component.ts文件中,Subscription的定义方式不正确,导致无法执行订阅操作。

解决方法:将Subscription的定义方式修改为正确的形式,并将_newCurrentProduct参数用括号包裹起来。

下面是修改后的代码示例:

在product.container.ts文件中添加以下代码:

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

在navbar.component.ts文件的ngOnInit()函数中添加以下代码:

import { Subscription } from "rxjs";
private subscription: Subscription;
ngOnInit(): void {
  this.initializeSubscribers();
  this.currentProduct = this._productContainer.getCurrentProduct();
  this.subscription = this._productContainer.getChangeCurrentProductSubject().subscribe((_newCurrentProduct) => {
    this.currentProduct = _newCurrentProduct;
  });
}

修改后的代码应该可以解决问题。

0
0 Comments

问题:在更改URL时,Subject未被触发的原因和解决方法

原因:

- 初始化时将逻辑放在NgModule中,这是不好的实践,模块不应该存在这样的逻辑。

- 在AdminModule的构造函数中更改currentProduct是行不通的,因为第一次加载后模块将不再加载,所以构造函数不会被调用。

- router.events没有被触发,可能是因为更新URL时整个应用程序被重新加载,包括navbar组件,因此组件也会被重建。

- 在navbar中使用this._router.url时,内容只是“/”,而不是“/forms”或“/admin”,即使URL是/forms或/admin。

解决方法:

- 将逻辑从NgModule中移出。

- 使用BehaviorSubject替代Subject。

- 在navbar组件中订阅url更改事件。

- 在navbar中定义“页面类型”参数,并将其传递给模块的根页面。

- 使用_location.path().startsWith()方法来获取URL路径。

以下是解决方法的代码示例:

// navbar.component.ts
import { Component } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Location } from '@angular/common';
import { ProductEnum } from './product.enum';
@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent {
  currentProduct: ProductEnum;
  constructor(private router: Router, private _location: Location) {
    if (this._location.path().startsWith(`/forms`)) {
      this.currentProduct = ProductEnum.Forms;
    } else if (this._location.path().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;
        }
      }
    });
  }
}

感谢您的理解和支持,希望以上解决方法对您有所帮助。

0