You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxJS提前赋值问题:emit/map完成前赋值导致默认值生效

问题描述

this.version始终获取到??后的默认值,原因是赋值操作执行时,.map操作尚未完成,导致后续读取this.version时仍是初始值。需要修改代码让赋值操作在emit/map完成后再执行,getVersionValues函数在app.component.ts中被调用时,emit/map还未完成,已提供完整代码。


解决方案

1. 修改VersionInfoService

将服务改为异步模式,利用RxJS数据流确保拿到版本数据后再返回结果:

import { Injectable } from '@angular/core';
import { VersionValues } from '@app-core/models/standard-filter.model';
import {ApiHelperService} from "@app-core/services/api-helper.service";
import {map, shareReplay} from "rxjs";

@Injectable({providedIn: 'root'})
export class VersionInfoService {
  // 用shareReplay缓存请求结果,避免重复发起API调用
  userInfo$ = this.apiHelperService.getUserInfo().pipe(
    shareReplay(1)
  );

  constructor(
    private apiHelperService: ApiHelperService
  ){}

  getVersionValues(): Observable<VersionValues> {
    return this.userInfo$.pipe(
      map(userInfo => {
        const versions = userInfo.versions || [];
        return {
          frontendVersion: versions?.[0] ?? "1.1.3",
          backendVersion: versions?.[1] ?? "1.1.3",
          javaVersion: versions?.[2] ?? "1.1.29",
          pentahoVersion: versions?.[3] ?? "1.1.3"
        };
      })
    );
  }
}

2. 修改AppComponent

调整按钮创建逻辑,等待异步版本数据返回后再初始化按钮:

import {AfterViewInit, Component, OnDestroy, OnInit, Type} from '@angular/core';
import {SmartSafeAny} from '@r-software/smart-ng/core/types';
import {
  BaseSlotComponent,
  BaseSlotInfoInputType,
  SmartBaseButton,
  SmartButtonSlotItem,
  SmartHeaderService,
  SmartSidebarNavigationService,
  SmartSlotItem
} from '@r-software/smart-ng/layout';
import {filter, takeUntil} from 'rxjs/operators';
import {Observable, Subject} from 'rxjs';
import {
  SmartHeaderBaseSlotButtonComponent
} from '@app-core/components/smart-header-base-slot-button/smart-header-base-slot-button.component';
import {SmartDialog} from '@r-software/smart-ng/dialog';
import {AccessModalComponent} from '@app-shared/components/access-modal/access-modal.component';
import {ApiHelperService} from '@app-core/services/api-helper.service';
import {SidebarHelperService} from '@app-core/services/utils/sidebar-helper.service';
import {ConfigurationService} from '@app-core/services/configuration/configuration.service';
import {SpotviewerUiWebMetaDataService} from 'meta-data/spotviewer-ui-web-meta-data.service';
import {FeatureStateService} from '@app-core/services/utils/feature-state.service';
import {ClassEnum} from '@app-core/models/enum/class.enum';
import {VersionInfoService} from "@app-core/services/utils/version-info.service";
import { VersionValues } from '@app-core/models/standard-filter.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
  get slotItems(): SmartSlotItem {
    return this._slotItems;
  }

  set slotItems(value: SmartSlotItem) {
    this._slotItems = value;
  }
  private _slotItems!: SmartSlotItem;
  buttonSlotItems!: SmartButtonSlotItem[];
  private baseButtons: SmartBaseButton[] = [];
  private destroy$: Subject<boolean> = new Subject<boolean>();

  constructor(
    private metaDataService: SpotviewerUiWebMetaDataService,
    private navigationHelperService: SidebarHelperService,
    private sidebarService: SmartSidebarNavigationService,
    private versionInfoService: VersionInfoService,
    private configurationService: ConfigurationService,
    private featureStateService: FeatureStateService,
    private apiHelperService: ApiHelperService,
    private headerService: SmartHeaderService,
    private dialog: SmartDialog
  ) {}

  ngOnInit(): void {
    this.featureStateService.mapFeaturesFromToken();
    this.headerService.setInfoSlot('SPOT');
    this.sidebarService.register([]);
    this.getReportTypes();
    
    // 等待版本数据返回后再创建按钮并设置到头部
    this.versionInfoService.getVersionValues()
      .pipe(takeUntil(this.destroy$))
      .subscribe(versionValues => {
        this.baseButtons = this.createBaseButton(versionValues);
        this.headerService.setButtonTemplateSlot(this.baseButtons);
      });

    const [textTemplate$, _textOnly$, buttons$]: Observable<SmartSafeAny>[] = this.headerService.__slotSource__;

    textTemplate$
      .pipe(
        filter((slot) => !!slot),
        takeUntil(this.destroy$)
      )
      .subscribe({
        next: (slot: [Type<BaseSlotComponent>, BaseSlotInfoInputType]) => {
          const [component, data] = slot;
          this._slotItems = new SmartSlotItem(component, data);
        }
      });

    buttons$.pipe(takeUntil(this.destroy$)).subscribe({
      next: (slots: SmartBaseButton[]) => {
        this.buttonSlotItems = slots.map((entry) => new SmartButtonSlotItem(SmartHeaderBaseSlotButtonComponent, entry));
      }
    });
  }

  ngAfterViewInit(): void {
    if (this.featureStateService.state.bigScrollbar) {
      const smartSidenavEl = document.querySelector('smart-sidenav');
      const scrollEl = document.querySelector('.content-container');
      if (smartSidenavEl && scrollEl) {
        smartSidenavEl.className += ClassEnum.BIG_SCROLLBAR;
        scrollEl.className += ClassEnum.BIG_SCROLLBAR;
      }
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next(true);
    this.destroy$.complete();
  }

  private getReportTypes(): void {
    this.navigationHelperService.sidebar$
      .pipe(takeUntil(this.destroy$))
      .subscribe(e => {
        this.sidebarService.addEntry(e);
      })
  }

  // 接收版本数据参数,直接使用异步获取的版本值
  private createBaseButton(versionValues: VersionValues): SmartBaseButton[] {
    const fe_version = `FEv${versionValues.frontendVersion}`;
    const be_version = `BEv${versionValues.backendVersion}`;
    const ja_version = `JAv${versionValues.javaVersion}`;
    const pe_version = `PEv${versionValues.pentahoVersion}`;

    return [
      {
        text: `${ja_version}|${pe_version}|${be_version}|${fe_version}`,
        type: 'version',
        callback: () => {
          // this is intentional
        }
      },
      {
        text: 'Befugnis',
        icon: 'key',
        primary: true,
        callback: () => {
          this.dialog.open(AccessModalComponent, {
            width: '800px',
            minHeight: '500px'
          });
        }
      }
    ];
  }
}

关键修改说明

  1. 服务层调整:

    • 移除同步versions变量,直接通过userInfo$数据流处理异步返回的版本数据
    • 使用shareReplay(1)缓存API请求结果,避免重复调用
    • getVersionValues改为返回Observable<VersionValues>,确保数据就绪后再返回结果
  2. 组件层调整:

    • 不再在构造函数中初始化按钮,改为在ngOnInit中等待版本数据返回后再创建
    • 修改createBaseButton方法,接收异步获取的版本数据参数,直接使用真实版本值

内容的提问来源于stack exchange,提问作者StingerWolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 10:35:06