[英]How to use snapshotChanges() method to get both key value and filter the data?
I'm working on an Angular Firebase Project, where I need to filter my database as well get the key values.我正在做一个 Angular Firebase 项目,我需要在其中过滤我的数据库并获取键值。 Currently I'm using valueChanges() method in my service code ( inside getUnreadBooks and getFavoriteBooks methods, as shown below ) to get the data and filter it.
目前我在我的服务代码中使用valueChanges()方法(在 getUnreadBooks 和 getFavoriteBooks 方法中,如下所示)来获取数据并对其进行过滤。 But it gives me key value as 'undefined', when I try to get key value inside my template file.
但是当我尝试在我的模板文件中获取键值时,它给我的键值为“未定义”。 I tried to go with snapshotChanges() method, but can't work around how to use it to get key values along with filtering the data.
我尝试使用snapshotChanges()方法,但无法解决如何使用它来获取键值以及过滤数据的问题。 Below are my Angular FirebaseService, home.component.ts ( in which I am injecting my service code ) and home.component.html (template file) Code respectively:
下面分别是我的 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 => Home.Component.ts 文件 =>
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 => Home.component.html 文件 =>
<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>
Declare a function to add id to your Object:声明一个函数以将 id 添加到您的对象:
documentToDomainObject = _ => {
const object = _.payload.doc.data();
object.id = _.payload.doc.id;
return object;
}
And use it in your getBooks method:并在您的 getBooks 方法中使用它:
getBooks(){
this.books = this.db.list('/books').snapshotChanges()
.pipe(map(actions => actions.map(this.documentToDomainObject)));
return this.books;
}
In my case I solved it by importing rxjs operator map, combined by.pipe在我的例子中,我通过导入 rxjs 运算符映射来解决它,结合 by.pipe
import { map } from 'rxjs/operators';
Example:例子:
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 };
});
}));
}
}
You need to import the rxjs operator map import { map } from 'rxjs/operators';您需要导入 rxjs 运算符 map import { map } from 'rxjs/operators'; // in rxjs 6 version
// 在 rxjs 6 版本中
I imported this import { map } from 'rxjs/operators'
and this solved my problem我
import { map } from 'rxjs/operators'
,这解决了我的问题
This is with angular 9 and it's working fine.this is set up in the service.ts and get the data from particular.ts file and just normally reader the data into template这是 angular 9 并且工作正常。这是在 service.ts 中设置的,并从 particular.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;
})));
}
particular.ts特别的.ts
constructor(private productService: ProductService) {
this.products$ = this.productService.getAll();
}
particular.html特别的.html
<tr *ngFor="let product of products$ | async" >
<td> {{ product.title }}</td>
<td> {{ product.price }}</td>
this.data.list('/expenseCategories').snapshotChanges().forEach(snapshot=> { snapshot.forEach(keys => { TransactionService.expenseCategories.push(keys.payload.key); }) });
Simple and effective solution: You will get both id and data简单有效的解决方案:您将同时获得 id 和 data
Add it in your service file in header part将它添加到标题部分的服务文件中
import { map } from 'rxjs/operators';
your getBooks method:你的 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
};
})
));
}
From the Firebase docs, I see that you cannot get the key when using valueChanges()
, you can only get it when using snapshotChanges()
.从 Firebase 文档中,我看到使用
valueChanges()
时无法获取密钥,只能在使用snapshotChanges()
时获取。
Building on Neelaka's answer, if you're using Angular 12 and the latest version of firebase, if you have a form that uses the (keyup)
event binding you can get the key and also filter like so:基于 Neelaka 的回答,如果您使用的是 Angular 12 和最新版本的 firebase,如果您有一个使用
(keyup)
事件绑定的表单,您可以获得密钥并像这样进行过滤:
In your product.services.ts
file:在您的
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};
})
}));
}
In admin-products.component.ts
file:在
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();
}
}
In admin-products.html
在
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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.