Reputation: 793
I'm making my first App on Angular. I trying to filter a list of book objects by the gender attribute. I am having difficulty sharing data between components: the filteredData
variable and the list of books FireBaseList
.
I am trying to pass the filteredData
variable from fixed-nav.component
to books-grid.component
. From my research, I know I need to make the books-grid.component
"bookList" observable of any changes and have the bookList
on fixed-nav.component.ts
emit an event on any changes on this.bookList
However, I am unable to achieve this. I know there are many questions about observables already but none use Firebase. Hope anyone out there can help me, THANKS!!
fixed-nav.component that I use as filter
import { Component, OnInit } from '@angular/core';
import { BookService } from '../../../services/book.service';
import { Book } from '../../../models/book';
@Component({
selector: 'fixed-nav',
templateUrl: './fixed-nav.component.html',
styleUrls: ['./fixed-nav.component.css']
})
export class FixedNavComponent implements OnInit {
Genders: string[];
bookList: Book[];
constructor(private bookService: BookService) {
this.Genders = ["Historia","Literatura", "Infantil", "Juvenil","Poesía","Narrativa"];
}
filterByGender(gender: string){
this.bookService.getBooks() // FIREBASE
.snapshotChanges()
.subscribe(item => {
this.bookList = [];
item.forEach(element => {
let x = element.payload.toJSON();
x["$key"] = element.key;
this.bookList.push(x as Book)
})
const filteredData = this.bookList.filter( function(element){
return element.gender == gender;
});
return filteredData; // I WANT TO SHARE THIS DATA
})
}
ngOnInit() {
}
}
books-grid.component.ts
import { Component, OnInit } from '@angular/core';
import { BookService } from '../../services/book.service';
import { Book } from '../../models/book';
@Component({
templateUrl: './books-grid.component.html',
styleUrls: ['./books-grid.component.css']
})
export class BooksGridComponent implements OnInit {
bookList: Book[];
constructor(private bookService: BookService) {}
ngOnInit() {
this.bookService.getBooks() // FIREBASE
.snapshotChanges()
.subscribe(item => {
this.bookList = [];
item.forEach(element => {
let x = element.payload.toJSON();
x["$key"] = element.key;
this.bookList.push(x as Book)
})
// SHARED DATA HERE
})
}
}
book.service.ts
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { Book } from '../models/book'; // Model
@Injectable({
providedIn: 'root'
})
export class BookService {
bookList: AngularFireList<any>;
selectedBook: Book = new Book(); // Temporally save selected Book
constructor(private firebase: AngularFireDatabase) { }
getBooks(){
return this.bookList = this.firebase.list('books');
}
}
books.model.ts
export class Book {
$key: string;
title: string;
author: string;
gender: string;
language: string;
image: string;
likes: number;
price: number;
new: boolean;
}
Upvotes: 5
Views: 6124
Reputation: 1406
you could utilize another shared service, where you update the booklist and then subscribe to any change event of this filtered booklist from your BooksGridComponent or any other component in need. I edited your code a little bit.
Something like this:
Create a new Service, where you return the filtered BooksList as an Observable, so any component can subscribe to it
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs'; // For rxjs 6
@Injectable({
providedIn: 'root'
})
export class SharedDataService {
private filteredBookList: Subject<Book[]> = new Subject<Book[]>();
constructor() {}
public getFilteredBookList(): Observable<Book[]> {
return this.filteredBookList.asObservable();
}
public setFilteredBookList(books: Book[]): void {
this.filteredBookList.next(books);
}
}
fixed-nav.component.ts:
Here you simply call the SharedDataService and set the filteredBookList.
this.sharedDataService.setFilteredBookList(filteredData);
And now in your books-grid.component.ts:
Here you are going to subscribe to any changes of the filteredBookList
this.sharedDataService.getFilteredBookList().subscribe((books: Book[]) => {
// Do Something with the filtered BookList from SharedDataService
})
Upvotes: 2
Reputation: 8712
In your book.service.ts
create a filterdData
variable and function to set filterdData
like below. Import Subject
using import { Subject } from 'rxjs';
filteredData = new Subject<any>();
setFilteredData(data) {
this.filteredData.next(data);
}
And then in your fixed-nav.component.ts
after done filtration set that filtered data like below
this.bookService.setFilteredData(filteredData);
Finally subscribe to the filteredData
in book.service.ts
from books-grid.component.ts
like below and assign the data into variable that you want.
constructor(private bookService: BookService) {
bookService.filteredData.subscribe((data)=>{
// Assign the data into variable that you want e.g this.filteredData = data;
})
}
Hope this will helps you!
Upvotes: 7