I have several components at work here; App
, Column
which contains a list of Task
components, and ViewTask
which get displayed when user clicks on a Task
. I also have a service class that contain my observable.
UiService Class
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UiService {
constructor() { }
private taskDisplaySubject = new Subject<any>();
taskDisplay$ = this.taskDisplaySubject.asObservable();
showTask(taskData: any) {
this.taskDisplaySubject.next(taskData);
console.log(`showTask was called`);
}
}
Here are my Column
HTML template and its TS
<div >
<header >
<h3 >
{{ columnName }} <span >({{ numOfTasks }})</span>
</h3>
</header>
<div >
<app-task
*ngFor="let task of tasks"
[task]="task"
[columnOfTask]="columnName"
(click)="onTaskClick(task)"
></app-task>
</div>
</div>
ColumnComponent Class
import { Component, Input, OnInit } from '@angular/core';
import { HttpService } from 'src/app/services/http.service';
import { UiService } from 'src/app/services/ui.service';
@Component({
selector: 'app-column',
templateUrl: './column.component.html',
styleUrls: ['./column.component.css'],
})
export class ColumnComponent implements OnInit {
constructor(private http: HttpService, private uiService: UiService) {}
ngOnInit(): void {
}
onTaskClick(taskObject: any) {
this.uiService.showTask(taskObject);
}
}
Now I have two subscriptions to that observable in two different components: app
and view-task
The problem is the callback function of the subscription in app
works but the one of the subscription in view-task
doesn’t. Why is that ? Shouldn’t I see two instances of the task object show up in the console ?
AppComponent
import { Component, Output } from '@angular/core';
import { UiService } from './services/ui.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'task-management-frontend';
@Output() showBoardsModal: boolean = false;
showDeleteModal: Boolean = false;
deleteModalType!: string;
showSidebar = false;
showTask = false;
constructor(private uiService: UiService) {}
ngOnInit(): void {
this.uiService.taskDisplay$.subscribe((taskData) => {
this.showTask = true;
console.log(taskData);
})
this.uiService.toggleEmitted$.subscribe(isShown => {
this.showSidebar = isShown;
})
}
ViewTaskComponent
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { HttpService } from 'src/app/services/http.service';
import { UiService } from 'src/app/services/ui.service';
@Component({
selector: 'app-view-task',
templateUrl: './view-task.component.html',
styleUrls: ['./view-task.component.css'],
})
export class ViewTaskComponent implements OnInit {
taskId!: string;
taskTitle!: string;
taskDescription!: string;
currentColumn!: string;
columns!: any[];
columnId!: string;
boardId!: string;
subtasks = [];
numOfSubtasks!: number;
numOfSubtasksDone = 0;
showColumnDropdown: boolean = false;
showEditDropdown: boolean = false;
constructor(
private route: ActivatedRoute,
private http: HttpService,
private ui: UiService
) {}
ngOnInit(): void {
this.ui.taskDisplay$.subscribe((taskData) => {
console.log(taskData);
});
this.boardId = this.ui.boardId;
}
app.component.html
<div >
<aside *ngIf="showSidebar">
<app-sidebar></app-sidebar>
</aside>
<app-titlebar
(showBoardsModal)="onToggleBoardsModal()"
(showDeleteModal)="onToggleDeleteModal($event)"
[displayBoardsModal]="showBoardsModal"
[ngClass]="{ 'enlarge-titlebar': !showSidebar }"
></app-titlebar>
<div [ngClass]="{ 'enlarge-main': !showSidebar }">
<router-outlet></router-outlet>
</div>
<app-view-task *ngIf="showTask"></app-view-task>
<app-boards-modal
(hideModalEvent)="onToggleBoardsModal()"
*ngIf="showBoardsModal"
></app-boards-modal>
<app-delete-modal
*ngIf="showDeleteModal"
(hideDeleteModal)="onToggleDeleteModal()"
[deleteModalType]="deleteModalType"
></app-delete-modal>
<button *ngIf="!showSidebar" (click)="displaySidebar()">
<svg width="16" height="11" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.815 4.434A9.055 9.055 0 0 0 8 0 9.055 9.055 0 0 0 .185 4.434a1.333 1.333 0 0 0 0 1.354A9.055 9.055 0 0 0 8 10.222c3.33 0 6.25-1.777 7.815-4.434a1.333 1.333 0 0 0 0-1.354ZM8 8.89A3.776 3.776 0 0 1 4.222 5.11 3.776 3.776 0 0 1 8 1.333a3.776 3.776 0 0 1 3.778 3.778A3.776 3.776 0 0 1 8 8.89Zm2.889-3.778a2.889 2.889 0 1 1-5.438-1.36 1.19 1.19 0 1 0 1.19-1.189H6.64a2.889 2.889 0 0 1 4.25 2.549Z"
fill="#FFF"
/>
</svg>
</button>
</div>
CodePudding user response:
The app-view-task
is late in subscribing to the values of subject that is why it's not showing values in app-view-task
.
As a workaround you can use ReplaySubject
instead of Subject
import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class UiService {
constructor() {}
private taskDisplaySubject = new ReplaySubject<any>(1);
taskDisplay$ = this.taskDisplaySubject.asObservable();
showTask(taskData: any) {
this.taskDisplaySubject.next(taskData);
console.log(`showTask was called`);
}
}