I have problem with understanding rxjs Observable cooperation with Angular components and their lifecycles (?). I will now describe code pasted below.
I got CartComponent, which holds array of files that have been added to cart. There is service that provides observables that add or remove files from filesArray (i use checkbox to add/remove). After adding a couple of files to cart, I expected that I would be able to use filesArray in SearchComponent (I used DI). Unfortunately, filesArray is empty in that scope, despite it's content is displayed in cart view properly. I don't understand such behavoir.
Why array is empty and how can I fix that problem? Please help.
CartComponent:
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent implements OnInit, OnDestroy {
filesArray: file[] = [];
constructor(private modalService: NgbModal, private cartService: CartService) {
}
open(content) {
this.modalService.open(content);
}
ngOnInit(): void {
this.cartService.addFileToCart$.pipe(
takeUntil(this.componentDestroyed)
).subscribe(file => {
this.filesArray = [...this.filesArray, file];
});
this.cartService.removeFileFromCart$.pipe(
takeUntil(this.componentDestroyed)
).subscribe(file => {
const fileIndex = this.filesArray.indexOf(file);
this.filesArray.splice(fileIndex,1);
});
}
private componentDestroyed: Subject<void> = new Subject();
ngOnDestroy(): void {
this.componentDestroyed.next();
this.componentDestroyed.unsubscribe();
}
}
SearchComponent:
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
constructor(private cartComponent: CartComponent) {
}
private checkOrderedFiles() {
console.log(this.cartComponent.pcFilesArray); //empty
}
CartService:
@Injectable({
providedIn: 'root'
})
export class CartService {
addFileToCart$: Subject<PCFile> = new Subject();
removeFileFromCart$: Subject<PCFile> = new Subject();
constructor() { }
}
Checkbox change event handler - I emit values to subjects here:
addOrRemoveFileFromCart(checkbox, item) {
if(checkbox.checked) {
this.cartService.addFileToCart$.next(item);
} else {
this.cartService.removeFileFromCart$.next(item);
}
}
EDIT:
public readonly files = this.cartService.addFileToCart$.pipe(
scan((filesArray: any, file) => [...filesArray, file], []),
share()
);
template
<div *ngFor="let file of files | async">
{{file.id}}
</div>
Subject, did you forget to add a snippet of a file? Also, be aware of usingSubjectswithout a good reason or without knowing what it exactly does. They can be abused easily and there's plenty of creation operators able to do the exact same thing. Just be mindful when using them and try not to expose too much of their API to your components and services.