首页 > 解决方案 > Angular Subject 多个不需要的订阅在组件之间进行对话

问题描述

我正在学习主题以及如何使用它在组件之间进行对话。

这是我的设置

消息总线.service.ts

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class MessageBusService {
  private subject: Subject<any>;

  constructor() {
   this.subject = new Subject<any>();
  }

  sendMessage(type: string, data?: any) {
    this.subject.next({ type, data });
  }

  clearMessage() {
    this.subject.next();
  }

  getMessage(): Observable<any> {
    return this.subject.asObservable();
  }
}

然后我有一个type.component.ts我目前仅用于单击 UI 中的按钮并打开一个模式。


  constructor(
    private contentTypeService: ContentTypeService,
    private messageBusService: MessageBusService,
    private dialog: MatDialog,
  ) {
    this.contentTypes = new MatTableDataSource([]);
    this.initSubscriptions();
    this.contentTypes.sort = this.sort;
  }

  ngOnInit(): void {
    this.loadContentTypes();
  }

  sortData() {
    this.contentTypes.sort = this.sort;
  }

  private initSubscriptions() {
    this.subscriptions = [
      this.messageBusService
        .getMessage()
        .subscribe(message => {
          if (!message) return;

          if (message.type == SEARCH_VALUE_CHANGED) {
            this.contentTypes.filter = message.data.trim().toLowerCase();
          } else if (message.type == PAGE_HEADER_CREATE_CLICKED) {
            this.openCreateModal();
          }
        })
    ]
  }

  openCreateModal() {
    const dialogRef = this.dialog.open(ContentTypeModalComponent, {
      data: {
        title: 'Content Type',
      },
      width: '550px',
      // height: '530px',
    });

    dialogRef.afterClosed().subscribe(result => {
      console.log(`Dialog result: ${result}`);
    });
  }

我的 Modal 由一个基本的可重用 modal 组成,它只定义页眉和页脚,并通过 . 因此,为了使事情更短,我将只在此处添加组件特定的模式,该模式会报告回我的 type.component.ts,这是我想要然后对模式中的结果执行某些操作的地方。

conten_type-modal.component.ts

import { Component, OnInit, Inject, Input } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import * as _ from 'lodash';
import { FormGroup, FormArray, FormBuilder, Validators } from '@angular/forms';
import { MessageBusService } from '../../../shared/services/message-bus.service';
import { MODAL_CREATE_CLICKED, MODAL_CANCEL_CLICKED, MODAL_CLOSE_CLICKED } from '../../../shared/constants/modal-events';
import { Subscription } from 'rxjs';

@Component({
  selector: 'content_type-modal',
  templateUrl: './content_type-modal.component.html',
  styleUrls: ['./content_type-modal.component.scss']
})
export class ContentTypeModalComponent implements OnInit {
  form: FormGroup;
  subscriptions: Subscription[];//Use array if multiple subs

  constructor(
    @Inject(MAT_DIALOG_DATA) public data,
    private messageBusService: MessageBusService,
    public dialogRef: MatDialogRef<ContentTypeModalComponent>,
    private fb: FormBuilder,
  ) {
    this.form = this.fb.group({
      name: [null, Validators.compose([Validators.required, Validators.maxLength(40)])],
      weightToVolumeRatio: [null, Validators.min(0)],
    });

    this.subscriptions = [
      this.messageBusService
        .getMessage()
        .subscribe(message => {
          if (!message) return;
          console.log("got ", message);
          if (message.type === MODAL_CREATE_CLICKED) {
            this.save();
          } else if (message.type === MODAL_CLOSE_CLICKED) {
            this.closeModal();
          }
        })
    ]
  }

  ngOnInit() {

  }

  save() {
    console.log(this.form.value);
    this.dialogRef.close(this.form.value);
  }

  ngOnDestroy(): void {
    // unsubscribe to any subscriptions ensure no memory leaks
    // this.subscriptions.forEach(subscription => subscription.unsubscribe());
  } 

  closeModal() {
    this.dialogRef.close();
  }
}

现在我意识到拥有一个消息总线可能不是一个好主意,让所有东西都在不加选择的情况下运行,因此您订阅的数量超过了您可能关心的数量,但我稍后会拆分它。

我的问题是,当我单击打开模式时,说我取消(中止)并因此关闭模式,然后我再次打开它,输入一些信息,然后按创建(保存)然后按我的主要组件 type.component.ts使用消息类型 MODAL_CREATE_CLICKED 两次(或打开和关闭对话框的 x 次)获取订阅回调。

if (message.type === MODAL_CREATE_CLICKED) {
            this.save();
          }

有人可以解释一下为什么会这样吗?我很困惑……

标签: angularsubject

解决方案


这里不是缺少代码吗?

你在哪里做this.messageBusService.sendMessage(type: string, data?: any)这个,任何用主题初始化的观察者都应该被调用。

如果这是整个代码。您可能正在获得初始主题值。

您不断收到消息增加的原因是因为您没有关闭/结束观察者和主题之间的连接。

例子:

modal_instance_1 这会初始化订阅。

您关闭模式,但订阅仍在内存中。

modal_instance_2 这会初始化另一个订阅。

但您仍有第一个订阅可用。

使用 rxjs observables 等时的经验法则是决定您希望该订阅可用多长时间。

示例:一旦主题发出第一个值,关闭连接。

  this.messageBusService.getMessage()
    .pipe(take(1)) // can be x amount of times.
    .subscribe(message => {
      ...    
    })

一旦组件被销毁,关闭连接。

  private _destroy$: Subject<any> = new Subject()

  constructor() {}

  ...

  this.messageBusService.getMessage()
    .pipe(takeUntil(this._destroy$) // can be x amount of times.
    .subscribe(message => {
      ...    
    })

  ...

  ngOnDestroy() {
    this._destroy$.next()
    this._destroy$.complete()
  }

希望这会有所帮助:)


推荐阅读