Angular 组件未订阅可观察服务

问题描述 投票:0回答:1

我有一个 Angular 组件,它应该对服务中的可观察对象发出的更改做出反应,但它似乎没有按预期订阅或做出反应。我正在 Angular 项目的前端部分工作,我在其中使用

ngx-joyride
库创建了一个教程。该教程工作正常,但现在我需要在执行第六步后显示一个组件。问题是在这个网页中,您可以创建不同的平台,但是当您开始本教程时,没有显示平台,我的目标是显示一个硬编码的平台(使用动态组件
tutorial-platform.component
)。为此,我正在使用可观察到的我想要订阅的地方。

以下是我迄今为止所做工作的总结:

这是我的

tutorial.service.ts
,它是控制教程的服务,也是我创建可观察对象的服务:


// tutorial.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { JoyrideService } from 'ngx-joyride';
import { PlatformsService } from './platforms.service';
import { PlatformsComponent } from '../platforms.component';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class TutorialService {
  private currentStep: string = '0';
  // I create an instance 'Subject'
  private displayFakePlatformSubject = new Subject<void>();
  // I convert the 'Subject' in an 'Observable'
  displayFakePlatform$ = this.displayFakePlatformSubject.asObservable();

  constructor(
    private joyrideService: JoyrideService,
    private router: Router,
    private platformsService: PlatformsService,
  ) { }

  // Some more functions
  
  // Function to listen to an event
  fakePlatformDisplay() {
    console.log('entering fakePlatformDisplay()...');
    this.displayFakePlatformSubject.next();
  }
}

现在我们将看到教程的第6步,看看我们如何调用函数(

dyd.component.html
),调用下一个按钮的函数在
dyd.component.ts
中定义:

HTML

<div class="back-btn-div">
    <ng-template #prevButton>
      <button nbButton (click)="onPreviousStep()">Previous</button>
    </ng-template>
    <ng-template #nextButton>
      <button nbButton (click)="onNextStep()">Next</button>
    </ng-template>
    <button (click)="openBackWindow()"
    (next)="7"
    joyrideStep="6"
    title="Next step"
    stepPosition="bottom-end"
    [prevTemplate]="prevButton"
    [nextTemplate]="nextButton"
    ></button>
  </div>

TS

import { TutorialService } from "../platforms/services/tutorial.service";

@Component({
    selector: 'dyd-platforms',
    templateUrl: './dyd.component.html',
    styleUrls: ['./dyd.component.scss']
})

export class DydComponent implements OnInit {
  constructor(
        private tutorialService: TutorialService
    ) { }
  
    onNextStep() {
        let url: string;
        const currentStep = this.tutorialService.getCurrentStep();
        if (currentStep == '6') {
            url = '/platforms';
            console.log('Fake Platform has been displayed.');
            this.tutorialService.fakePlatformDisplay();
            console.log('-----------<>----------.');
        }
        else {url = '/editor';}
        const nextStep = (parseInt(currentStep) + 1).toString();
        this.tutorialService.navigateToStep(nextStep, url);
    }
}

正如您在

html
中看到的,当按下下一个按钮时,我们调用
ts
函数
onNextStep()
,并且该函数调用我们之前提到的
tutorialService.fakePlatformDisplay()

按下按钮时,我们也会进入下一步,在本例中是在另一个组件中(

platforms.component
),这是我们要显示动态组件的组件。首先我将展示动态组件:

tutorial-platform.component.html

<div class="card-row">
  <div class="card-col">
    <div>
      <nb-card size="small" class="platformListCard">
        <nb-card-body class="card-body">
          <!-- Some code here -->
        </nb-card-body>
      </nb-card>
    </div>
  </div>
</div>

这是

platforms.component
:

HTML;我为动态组件容器创建了一个 div;

<div>
  <ng-container #dynamicComponentContainer></ng-container>
</div>

TS

import { TutorialService } from './services/tutorial.service';
import { TutorialPlatformComponent } from "src/app/shared/components/tutorial-platform/tutorial-platform.component";
import { Subscription } from "rxjs";


@Component({
    selector: 'app-platforms',
    templateUrl: './platforms.component.html',
    styleUrls: ['./platforms.component.scss']
})
export class PlatformsComponent implements OnInit, AfterViewInit, OnDestroy {

    @ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer!: ViewContainerRef;
    private subscription: Subscription = new Subscription();

    constructor(        
        private tutorialService: TutorialService
    ) {  console.log('--> PlatformsComponent constructor called');}    

    ngAfterViewInit() {
        console.log('ngAfterViewInit called in PlatformsComponent');
        this.subscription.add(
            this.tutorialService.displayFakePlatform$.subscribe(() => {
                console.log('displayFakePlatform$ triggered');
                this.displayTutorialPlatform();
            })
        );
    }

    ngOnDestroy() {
        console.log('ngOnDestroy called in PlatformsComponent');
        this.subscription.unsubscribe();
    }
    
    displayTutorialPlatform() {
        // Create the component
        this.dynamicComponentContainer.createComponent(TutorialPlatformComponent);
        console.log("dynamicComponentContainer created");
    }

看过所有代码后,这是我执行时得到的日志:

Fake Platform has been displayed.               dyd.component.ts:295:20
entering fakePlatformDisplay()...               tutorial.service.ts:49:12
-----------<>----------.                        dyd.component.ts:297:20
--> PlatformsComponent constructor called       platforms.component.ts:78:17
ngAfterViewInit called in PlatformsComponent    platforms.component.ts:81:16

正如你所看到的,它到达了函数

ngAfterViewInit
,但它没有执行订阅部分,为什么会发生这种情况?

ngAfterViewInit() {
        console.log('ngAfterViewInit called in PlatformsComponent');
        // ****** IT STOPS HERE ******
        this.subscription.add(
            this.tutorialService.displayFakePlatform$.subscribe(() => {
                console.log('displayFakePlatform$ triggered');
                this.displayTutorialPlatform();
            })
        );
    }
angular typescript service components observable
1个回答
0
投票

这可能是一个时间问题,请尝试使用 BehaviourSubject 代替。

private displayFakePlatformSubject = new BehaviourSubject<string>('');

然后检查主题是否有值,然后触发代码。

ngAfterViewInit() {
    console.log('ngAfterViewInit called in PlatformsComponent');
    // ****** IT STOPS HERE ******
    this.subscription.add(
        this.tutorialService.displayFakePlatform$.subscribe((data: string) => {
            if(!data) return;
            console.log('displayFakePlatform$ triggered');
            this.displayTutorialPlatform();
        })
    );
}

然后,当您发出时,将代码更改为下面的代码。

  // Function to listen to an event
  fakePlatformDisplay() {
    console.log('entering fakePlatformDisplay()...');
    this.displayFakePlatformSubject.next('ready');
  }
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.