我正在开发一个Angular Firebase项目,我需要过滤我的数据库并获取关键值。目前我在我的服务代码(里面的getUnreadBooks和getFavoriteBooks方法,如下所示)中使用 valueChanges()方法来获取数据并对其进行过滤。但是当我尝试在模板文件中获取键值时,它给我的关键值为'undefined'。我尝试使用 snapshotChanges()方法,但无法解决如何使用它来获取键值以及过滤数据。下面是我的Angular FirebaseService,home.component.ts(我注入了我的服务代码)和home.component.html(模板文件)代码:
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@Injectable()
export class FirebaseService {
books: Observable<any[]>;
unreadBooks;
favoriteBooks;
constructor(private db: AngularFireDatabase) {}
getBooks(){
this.books = this.db.list('/books').valueChanges() as Observable<any[]>;
return this.books;
}
getFavoriteBooks(){
this.favoriteBooks = this.db.list('/books').valueChanges() as Observable<any[]>;
this.favoriteBooks = this.favoriteBooks.map(books => {
const topRatedBooks = books.filter(item => item.rate>4);
return topRatedBooks;
})
return this.favoriteBooks;
}
getUnreadBooks(){
this.unreadBooks = this.db.list('/books').valueChanges() as Observable<any[]>;
this.unreadBooks = this.unreadBooks.map(books => {
const ub = books.filter(item => item.dateread == null);
return ub;
})
return this.unreadBooks;
}
}
Home.Component.ts file =&gt;
import { Component, OnInit } from '@angular/core';
import { FirebaseService } from '../../services/firebase.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
//favorite Books
favoriteBooks: any;
unreadBooks: any;
constructor(private firebaseService: FirebaseService) { }
ngOnInit() {
this.firebaseService.getFavoriteBooks()
.subscribe(favBooks => {
this.favoriteBooks = favBooks;
console.log(this.favoriteBooks);
})
this.firebaseService.getUnreadBooks()
.subscribe(ubBooks => {
this.unreadBooks = ubBooks;
console.log('Unread Books:', this.unreadBooks);
})
}
}
Home.component.html file =&gt;
<mat-toolbar>
My Top Rated Books
</mat-toolbar>
<mat-grid-list cols="3">
<mat-grid-tile *ngFor="let book of favoriteBooks">
<mat-card>
<mat-card-header>
<mat-card-title>
<h4>{{book.title}}</h4>
</mat-card-title>
</mat-card-header>
<img mat-card-image src="{{book.imageUrl}}" alt="{{book.title}}">
<mat-card-actions>
<button mat-button mat-raised-button class="detailsButton" [routerLink]="['/book/'+book.$key]">
<i class="material-icons">visibility</i>Book Details</button>
<button mat-button mat-raised-button class="editButton" [routerLink]="['/editbook/'+book.$key]">
<i class="material-icons">mode_edit</i>Edit Book</button>
</mat-card-actions>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
<mat-toolbar>
Books I have not read yet
</mat-toolbar>
<mat-grid-list cols="3">
<mat-grid-tile *ngFor="let book of unreadBooks">
<mat-card>
<mat-card-header>
<mat-card-title>
<h4>{{book.title}}</h4>
</mat-card-title>
</mat-card-header>
<img mat-card-image src="{{book.imageUrl}}" alt="{{book.title}}">
<mat-card-actions>
<button mat-button mat-raised-button class="detailsButton" [routerLink]="['/book/'+book.$key]">
<i class="material-icons">visibility</i>Book Details</button>
<button mat-button mat-raised-button class="editButton" [routerLink]="['/editbook/'+book.$key]">
<i class="material-icons">mode_edit</i>Edit Book</button>
</mat-card-actions>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
答案 0 :(得分:6)
声明一个向您的Object添加id的函数:
documentToDomainObject = _ => {
const object = _.payload.doc.data();
object.id = _.payload.doc.id;
return object;
}
并在你的getBooks方法中使用它:
getBooks(){
this.books = this.db.list('/books').snapshotChanges()
.pipe(map(actions => actions.map(this.documentToDomainObject)));
return this.books;
}
答案 1 :(得分:3)
您需要导入rxjs运算符映射 从'rxjs / operators'导入{map}; //在rxjs 6版本中
答案 2 :(得分:2)
在我的情况下,我通过导入rxjs运算符映射(由.pipe组合)解决了该问题
import { map } from 'rxjs/operators';
示例:
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AngularFirestore } from 'angularfire2/firestore';
import { IdeaService } from './app.service';
import { config } from './app.config';
import { Idea } from './app.model';
import {
AngularFirestoreDocument,
AngularFirestoreCollection
} from 'angularfire2/firestore';
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let idea of ideas | async">
<pre>{{ idea | json }}</pre>
</li>
</ul>
`
})
export class AppComponent {
public ideasCollection: AngularFirestoreCollection<Idea>;
public ideas: Observable<any[]>;
constructor(db: AngularFirestore, private ideaService: IdeaService) {
this.ideasCollection = db.collection<Idea>(config.collection_endpoint);
this.ideas = this.ideasCollection.snapshotChanges().pipe(
map(actions => {
return actions.map(a => {
const data = a.payload.doc.data() as Idea;
const id = a.payload.doc.id;
return { id, ...data };
});
}));
}
}
答案 3 :(得分:0)
this.data.list('/expenseCategories').snapshotChanges().forEach(snapshot=> {
snapshot.forEach(keys => {
TransactionService.expenseCategories.push(keys.payload.key);
})
});
答案 4 :(得分:0)
我导入了这个
import { map } from 'rxjs/operators'
这解决了我的问题
答案 5 :(得分:0)
这是与角度9一起使用的,它工作正常。这是在service.ts中设置的,并从特定的.ts文件中获取数据,并且通常将数据读取到模板中
getAll() {
return this.database.list('/products').snapshotChanges()
.pipe(map( action => action
.map(a => {
const key = a.payload.key;
const data = a.payload.val();
return data;
})));
}
特定.ts
constructor(private productService: ProductService) {
this.products$ = this.productService.getAll();
}
特定的.html
<tr *ngFor="let product of products$ | async" >
<td> {{ product.title }}</td>
<td> {{ product.price }}</td>
答案 6 :(得分:0)
简单有效的解决方案:您将同时获得ID和数据
将其添加到标题部分的服务文件中
import { map } from 'rxjs/operators';
您的getBooks方法:
getBooks(){
return this.books = this.db.list('/books').snapshotChanges()
.pipe(map(action => action
.map(a => {
let obj:any = a.payload.doc.data()
return {
...obj,
id: a.payload.doc.id
};
})
));
}
答案 7 :(得分:0)
从 Firebase 文档中,我看到使用 valueChanges()
时无法获取密钥,只能在使用 snapshotChanges()
时获取它。
根据 Neelaka 的回答,如果您使用的是 Angular 12 和最新版本的 firebase,如果您有一个使用 (keyup)
事件绑定的表单,您可以获得密钥并进行如下过滤:>
在您的 product.services.ts
文件中:
getAll(){
return this.db.list('/products').snapshotChanges().pipe(map(actions => {
return actions.map(a => {
const key = a.payload.key;
const data = a.payload.val();
return {data, key};
})
}));
}
在 admin-products.component.ts
文件中:
export class AdminProductsComponent implements OnDestroy {
products!: { title: string; }[] | any;
filteredProducts!: any[];
subscription: Subscription;
constructor(private productService: ProductService) {
this.subscription = this.productService.getAll().subscribe(products => {
this.filteredProducts = this.products = products;
});
}
filter(query: string){
this.filteredProducts = (query) ?
this.products.filter((p: { data: {title:string}, key: string }) => p.data.title.toLocaleLowerCase().includes(query.toLocaleLowerCase())) :
this.products;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
在admin-products.html
<br>
<p>
<a routerLink="/admin/products/new" class="btn btn-primary">New Product</a>
</p>
<br>
<p>
<input #query (keyup)="filter(query.value)" type="text" class="form-control" placeholder="Search...">
</p>
<br>
<table class="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Price</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of filteredProducts">
<td>{{ p.data.title }}</td>
<td>{{ p.data.price }}</td>
<td>
<a [routerLink]="['/admin/products/', p.key]">Edit</a> ✍️
</td>
<td>
<a (click)="delete(p.key)" id="delete">Delete</a> ?
</td>
</tr>
</tbody>
</table>