我有一个 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();
})
);
}
这可能是一个时间问题,请尝试使用 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');
}