将BehaviorSubject值作为参数传递

时间:2019-02-18 20:31:12

标签: angular rxjs6 behaviorsubject

我有一个Angular组件,其BehaviourSubject初始化为当前月份:

textLabel: string;

private monthIndex$: BehaviorSubject<number>;

private MONTHS = [
"Gennaio",
"Febbraio",
"Marzo",
"Aprile",
"Maggio",
"Giugno",
"Luglio",
"Agosto",
"Settembre",
"Ottobre",
"Novembre",
"Dicembre"
];

constructor(private listService: ShoppingListService) {}

ngOnInit() {
  this.monthIndex$ = new BehaviorSubject<number>(new Date().getMonth());

  // Like this it does not display the label
  this.setMonthLabel(this.monthIndex$.value); 

  this.model$ = this.monthIndex$.pipe(
    switchMap((monthValue: number) => {
      //    this.setMonthLabel(monthValue);  // This way it works!
      return this.listService.getHistoryChartModel(monthValue);
    }),
    takeUntil(this.destroy$)
  );
}

private setMonthLabel(monthIndex: number) {
  this.textLabel = this.MONTHS[monthIndex];
}

setMonth(direction: number) {
  let monthIndex = this.monthIndex$.getValue();
  monthIndex += direction;
  monthIndex =
  monthIndex < 0 ? 0 : monthIndex > 11 ? 11 : monthIndex;

  this.monthIndex$.next(monthIndex);
  this.setMonthLabel(monthIndex);
}

和模板:

<div class="view-sel-container">
  <button
   color="primary" mat-icon-button
   (click)="setMonth(-1)"
   [disabled]="monthIndex === 0">
  <i class="material-icons">
    keyboard_arrow_left
  </i>
 </button>

 <span class="label-text" *ngIf="textLabel">{{ textLabel }}</span>

 <button
  color="primary" mat-icon-button
  (click)="setMonth(1)"
  [disabled]="monthIndex === 11">
  <i class="material-icons">
    keyboard_arrow_right
  </i>
 </button>

是否由于将BehavourSubject值传递给方法this.setMonthLabel(this.monthIndex$.value)而导致标签未显示在模板中的时间原因?

更新

Deborah Kurata使用get / set而不是BehaviourSubject提供的解决方案是最好的方法。我将原始问题/代码保持打开状态,因为仍然无法通过传递behaviourSubject值作为参数来理解为什么代码现在可以正常工作。

2 个答案:

答案 0 :(得分:1)

考虑使用不需要SubjectBehaviorSubject的类似内容:

组件

import { Component } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
  templateUrl: './history-chart.component.html'
})
export class HistorChartComponent {
  textLabel: string;
  model$: Observable<any>;

  private _monthIndex: number;
  get monthIndex(): number {
    return this._monthIndex;
  }
  set monthIndex(value: number) {
    console.log("setter called with: " + value);
    // Set the label
    this.setMonthLabel(value);
    // Get the data
    this.getMonthData(value);
    this._monthIndex = value;
  }

  private MONTHS = [
    "Gennaio",
    "Febbraio",
    "Marzo"
  ];

  constructor() { }

  ngOnInit() {
    // This calls the setter
    this.monthIndex = new Date().getMonth();
  }

  // Increment or decrement the month index
  // This calls the setter
  setMonth(value: number) {
    this.monthIndex += value;
  }

  private setMonthLabel(monthIndex: number) {
    this.textLabel = this.MONTHS[monthIndex];
  }

  private getMonthData(monthIndex: number): void {
    // Commented out because I don't have the service code
    //this.model$ = this.listService.getHistoryChartModel(monthIndex);

    // Faking out the call to the service
    this.model$ = of(
      { id: 1, value: "some data for month : " +  this.MONTHS[monthIndex] },
    );
  }
}

每次用户更改值或在代码中更改值时,都会自动调用设置器。因此,setter是执行任何需要响应更改的代码的好地方。

使用上面的代码,每当用户单击任意一个按钮时,就会在ngOnInt上检索月份数据。如果您在提供的stackblitz中没有看到此行为,请告诉我。

模板

<div class="view-sel-container">
    <button
   color="primary" mat-icon-button
   (click)="setMonth(-1)"
   [disabled]="monthIndex === 0">
  <i class="material-icons">
    keyboard_arrow_left
  </i>
 </button>

 <span class="label-text" *ngIf="textLabel">{{ textLabel }}</span>

 <button
  color="primary" mat-icon-button
  (click)="setMonth(1)"
  [disabled]="monthIndex === 11">
  <i class="material-icons">
    keyboard_arrow_right
  </i>
 </button>

<div>
<span class="label-text" *ngIf="textLabel">
 {{textLabel}}
</span>
</div>
<div *ngIf="(model$ | async) as model">
  <div>
  {{ model.value }}
  </div>
</div>

这是相关的堆叠闪电战:https://stackblitz.com/edit/angular-bpusk2

答案 1 :(得分:0)

this.monthIndex$ = new BehaviorSubject<number>(new Date().getMonth());

  // Like this it does not display the label
  this.setMonthLabel(this.monthIndex$.value); 

  this.model$ = this.monthIndex$.pipe(
    tap(monthValue => {
      this.setMonthLabel(monthValue);
      return this.listService.getHistoryChartModel(monthValue);
    }),
    takeUntil(this.destroy$)
  );
  1. 对于有副作用的任何东西,都应使用tap。
  2. 我不知道为什么管道中已经有值时为什么需要使用this.setMonthLabel(this.monthIndex$.value)
  3. this.setMonthLabel的作用是什么?