Reputation: 125
I have two components, one of them is a child route inside a of the main component html.
Whenever I select checkboxes of categories in the main component, I am assigning them to a variable(string array) in service. And in the child route, I am subscribing to an observable of this service variable. My goal is to update the child route's view to display the books of those categories only.
So shouldn't I be seeing the logs as and when the value of service variable gets changed (Because I have given console.log() in child component)? Doesn't subscribe get updated value everytime the value changes? And finally, does subscribe call the ngOnChanges() method? (To update the view)
My Code:- Parent Component.html:-
<div class="ui-g-12">
<p-checkbox
name="categories"
value="Science Fiction"
label="Science Fiction"
[(ngModel)]="selectedCategories"
(onChange)="categoryFilterSelect()"
></p-checkbox>
</div>
<div class="ui-g-12">
<p-checkbox
name="categories"
value="Horror"
label="Horror"
[(ngModel)]="selectedCategories"
(onChange)="categoryFilterSelect()"
></p-checkbox>
</div>
<div class="ui-g-12">
<p-checkbox
name="categories"
value="Suspense"
label="Suspense"
[(ngModel)]="selectedCategories"
(onChange)="categoryFilterSelect()"
></p-checkbox>
</div>
<div class="ui-g-12">
<p-checkbox
name="categories"
value="Romance"
label="Romance"
[(ngModel)]="selectedCategories"
(onChange)="categoryFilterSelect()"
></p-checkbox>
</div>
<div class="ui-g-12">
<p-checkbox
name="categories"
value="Action"
label="Action"
[(ngModel)]="selectedCategories"
(onChange)="categoryFilterSelect()"
></p-checkbox>
</div>
<div style="margin-top: 10%">
<router-outlet></router-outlet>
</div>
Parent Component.ts:-
selectedCategories: string[] = [];
//...
categoryFilterSelect(){
this.userService._filterByGenre = this.selectedCategories;
}
second component's ts:-(routed into of Parent Component.html)
export class HomeComponent implements OnInit {
allBooks: Book[] = [];
selectedCategories: string[];
filteredBooks: Book[];
constructor(private userService: UserService) {}
ngOnInit() {
//initially display all books
this.userService.getAllBooks().subscribe(data => {
this.allBooks = data;
this.filteredBooks = this.allBooks;
});
//This part not working
this.userService.filterByGenre.subscribe(data => {
this.selectedCategories = data;
//this line not working
console.log(this.selectedCategories);
//perform filter logic here and update the filteredBooks array based
// onselected categories
}
);
}
}
second component.html
<div class="container">
<div class="child" *ngFor="let book of filteredBooks">
....
</div>
</div>
service.ts
export class UserService {
_filterByGenre: string[] = [];
public get filterByGenre(): Observable<string[]> {
return of(this._filterByGenre);
}
}
console output:- [] (Because initially no categories are selected so this is logged).
My Git Repo:- https://github.com/Lucifer-77/ATL
Upvotes: 0
Views: 10782
Reputation: 58099
@Lucifer, the things don't work as you think. Angular is not magical. Don't worry about it, it's a common mistake at first. When you subscribe to an Observable, Angular not put a "big brother" to see what happens to the data. e.g. when we make a subscription of httpClient.get(url) that call to a dbs, any change of dbs Angular don't take account of this. (it can not do it).
So you need create a service that say that Angular take account the changes: you need make use of Subject of similar. Let me show a service that work
private _filterByGenre:string[];
private filterByGenreSource = new Subject<any>();
filterByGenreObservable=this.filterByGenreSource.asObservable();
get filterByGenre()
{
return this._filterByGenre
}
set filterByGenre(value) //when we use dataService.filterBtGenre=...
{
this._filterByGenre=value; //equal to the private variable
this.filterByGenreSource.next(value) //say to Angular that something change
}
You can subscribe to filterByGenreObservable
this.dataService.filterByGenreObservable.subscribe(data => {
this.selectedCategories = [...data]; //(*)
});
//(*) is we make simply this.selectedCategories=data, we can not see the data change
//so, I used the spread operator
If we make something like
this.dataService.filterByGenre = this.selectedCategories;
As we are using a setter, emit a new value
Well, I don't use p-checkbox, but you can be the code of this answer in this stackblitz
Update well, Obviously we want to make "something" when change the categories.
Imagine we has an array called allBooks, and we want filterted by categories selected. But first we are going to change the data we send to the user service to make more similar to p-checkbox, so I change my function categoryFileterSelect to send in an array not [true,false,false,true] else ["Horror","Science Fiction"]
categoryFilterSelect() {
this.dataService.filterByGenre =
this.options.filter((x, index) => this.selectedCategories[index]);
}
So, We can write
this.userService.filterByGenreObservable.subscribe(
data => {
this.filteredBooks=this.allBooks.filter(x=>data.indexOf(x.genre)>=0)
},
error => null,
() => console.log("error")
);
Well, I want to make at first observable a call with the value of this.userService.filterByGenre, so I go to use rxjs operator startWith so, finally my subscription becomes like
this.userService.filterByGenreObservable.pipe(
startWith(this.userService.filterByGenre))
.subscribe(
data => {
this.filteredBooks=data?this.allBooks.filter(x=>data.indexOf(x.genre)>=0)
:this.allBooks
},
error => null,
() => console.log("error")
);
Upvotes: 1
Reputation: 1020
Please try with the following call of filterByGenre() in the second component.
this.userService.filterByGenre().subscribe((data:string[]) => {
this.selectedCategories = data;
console.log(this.selectedCategories);
//perform filter logic here and update the filteredBooks array based
// onselected categories
}
Upvotes: 0