【问题标题】:Angular Observable, sharing data within componentsAngular Observable,在组件内共享数据
【发布时间】:2018-12-22 22:15:51
【问题描述】:

我正在 Angular 上制作我的第一个应用程序。我试图按性别属性过滤书籍对象列表。我在组件之间共享数据时遇到困难:filteredData 变量和书籍列表FireBaseList

我正在尝试将filteredData 变量从fixed-nav.component 传递给books-grid.component。根据我的研究,我知道我需要使 books-grid.component "bookList" 可观察到任何更改,并让 fixed-nav.component.ts 上的 bookListthis.bookList 上的任何更改上发出事件

但是,我无法做到这一点。我知道已经有很多关于 observables 的问题,但没有一个使用 Firebase。希望有大神能帮帮我,谢谢!!

我用作过滤器的fixed-nav.component

    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;
    }

【问题讨论】:

  • 考虑将任何过滤代码或共享列表移动到BookService。这样,您可以从那里共享完整或过滤的列表。任何使用BookService 的组件都可以使用它们。

标签: angular typescript firebase firebase-realtime-database observable


【解决方案1】:

在您的book.service.ts 中创建一个filterdData 变量和函数来设置filterdData,如下所示。使用import { Subject } from 'rxjs'; 导入Subject

 filteredData  = new Subject<any>();

  setFilteredData(data) {
    this.filteredData.next(data);
  }

然后在您的fixed-nav.component.ts 完成过滤后设置过滤数据,如下所示

 this.bookService.setFilteredData(filteredData);

最后从books-grid.component.ts 订阅book.service.ts 中的filteredData,如下所示,并将数据分配给您想要的变量。

 constructor(private bookService: BookService) {
     bookService.filteredData.subscribe((data)=>{
      // Assign the data into variable that you want e.g this.filteredData = data;
    })
 }

希望对你有帮助!

【讨论】:

  • 非常感谢,这正在工作!也想试试上面的选项,你认为它是更好的选择吗?所以我可以在任何其他组件中使用该服务
  • @Sergi 很高兴听到这个消息:)。是的,您也可以使用此服务的其他组件,它会正常工作
  • 嘿我有一个问题,每次我订阅更改时,它都会堆叠,就像它订阅所有事件一样,如何实例化 Subject() 所以它只订阅一次
  • 在你的组件上实现OnDestroy,在ngOnDestroy()内部取消订阅observable。例如首先声明一个subscription: ISubscription; 变量并分配this.subscription = bookService.filteredData.subscribe((data)=&gt;{ }) 和内部ngOnDestroy() 像这样使用this.subscription.unsubscribe();
【解决方案2】:

您可以使用另一个共享服务,在其中更新书单,然后从您的 BooksGridComponent 或任何其他需要的组件中订阅此过滤后的书单的任何更改事件。我稍微修改了你的代码。

类似这样的:

创建一个新服务,将过滤后的 BooksList 作为 Observable 返回,以便任何组件都可以订阅它

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:

这里您只需调用 SharedDataService 并设置过滤后的BookList。

this.sharedDataService.setFilteredBookList(filteredData); 

现在在您的 books-grid.component.ts 中:

在这里你要订阅filteredBookList的任何变化

this.sharedDataService.getFilteredBookList().subscribe((books: Book[]) => {
  // Do Something with the filtered BookList from SharedDataService
})

【讨论】:

  • 在导入 'rxjs/Rx' 时遇到问题;
  • 没有该导入应该可以正常工作。我编辑了答案!
猜你喜欢
  • 2018-09-27
  • 2023-03-10
  • 2020-03-14
  • 2019-08-04
  • 2017-04-15
  • 1970-01-01
  • 2018-10-12
  • 2018-10-09
相关资源
最近更新 更多