在我基于 firebase 和 firebase 的 Angular 项目中,我有这个表单,当我尝试编辑产品时,我可以访问每个产品的 id,但无法通过其他数据(标题、价格、类别...) 这是我的代码: 产品表单.html
<div class="row">
<div class="col-md-6">
<form (ngSubmit)="save(f.value)" #f="ngForm">
<div class="form-group">
<label for="id">Id</label>
<input [(ngModel)]="product.id" name="id" type="number" class="form-control" id="id" required #id="ngModel">
<div class="alert alert-danger" *ngIf="id.touched && id.invalid">The id is required !</div>
</div>
<div class="form-group">
<label for="title">Title</label>
<input [(ngModel)]="product.title" name="title" type="text" class="form-control" id="title" required #title="ngModel">
<div class="alert alert-danger" *ngIf="title.touched && title.invalid">Title is required !</div>
</div>
<div class="form-group">
<label for="price">Price</label>
<div class="input-group">
<input type="number" class="form-control" id="price" [(ngModel)]="product.price" #price="ngModel" name="price" required min="0">
<span class="input-group-text">$</span>
</div>
<div class="alert alert-danger" *ngIf="price.touched && price.invalid">
<div *ngIf="price.errors?.['required']">"price is required !"</div>
<div *ngIf="price.errors?.['pattern']">price must be a number</div>
<div *ngIf="price.errors?.['min']">price must be =>0 ! </div>
</div>
</div>
<div class="form-group">
<label for="category">Category</label>
<select class="form-control" id="category" [(ngModel)]="product.category" name="category" #category="ngModel" required>
<option value=""></option>
<option *ngFor="let category of categories$ " [value]="category.name">{{category.name}}</option>
</select>
<div class="alert alert-danger" *ngIf="category.touched && category.invalid">category is required!</div>
</div>
<div class="form-group">
<label for="imageUrl">Image Url</label>
<div class="input-group">
<span class="input-group-text">http://</span>
<input type="text" class="form-control" id="imageUrl" #imageUrl="ngModel" [(ngModel)]="product.imageUrl" name="imageUrl" required pattern="https?://.+">
</div>
</div>
<div class="alert alert-danger" *ngIf="imageUrl.touched && imageUrl.invalid">
<div *ngIf="imageUrl.errors?.['required']">image Url is Required!</div>
<div *ngIf="imageUrl.errors?.['pattern']">image Url is invalid! must start with http:// or https://...</div>
</div>
<br>
<button class="btn btn-primary" type="submit">Save</button>
</form>
</div>
<div class="col-md-6">
<div class="card" style="width: 20rem;">
<img [src]="imageUrl.value" class="card-img-top">
<div class="card-body">
<h5 class="card-title" style="color: dodgerblue;" >{{title.value}}</h5>
<p class="card-text">{{price.value | currency:'USD':true}}</p>
</div>
</div>
</div>
</div>
<div class="toast align-items-center text-white bg-primary border-0" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
Product Added succefully
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
产品形式.ts
import { Component,Inject, Input} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { CategoriesService } from '../../services/categories.service';
import { Router, RouterLink, ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { tap, take } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ChangeDetectorRef } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/compat/database';
import { ProductService } from 'src/app/services/product.service';
import { AngularFireStorage } from '@angular/fire/compat/storage';
import { AngularFirestore } from '@angular/fire/compat/firestore';
@Component({
selector: 'app-products-form',
templateUrl: './products-form.component.html',
styleUrl: './products-form.component.css'
})
export class ProductsFormComponent {
categories$:any;
products:any
product$:any;
private destroy$ = new Subject<void>();
product: any = {
id: '',
title: '',
price: '',
category:'',
imageUrl:''
};
constructor( categories: CategoriesService,private ProductService :ProductService, private router: Router,private db:AngularFireDatabase, private afs:AngularFirestore ,private route:ActivatedRoute,private cdr: ChangeDetectorRef,)
{
this.db.list('/categories').valueChanges().pipe(
tap(data => {
this.categories$ = data;
})
).subscribe(
() => {
console.log(this.categories$);
},
);
this.afs.collection('/products/').valueChanges().pipe(
tap(data => {
this.products = data;
})
).subscribe(
() => {
console.log(this.products);
},
);
const id = this.route.snapshot.paramMap.get('id');
if (id) {
console.log(id);
this.ProductService.getProductWithKey(id).pipe(takeUntil(this.destroy$))
.subscribe(productData => {
this.product = productData;
console.log(this.product)
});
}
}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
if (id) {
console.log(id);
this.ProductService.getProductWithKey(id).pipe(takeUntil(this.destroy$))
.subscribe(productData => {
console.log(productData);
this.product = productData;
});
}
}
save(product:any){
this.ProductService.create(product);
this.router.navigate(['/admin/products']);
console.log(product);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
产品.服务.ts
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/compat/database';
import {AngularFirestore,AngularFirestoreDocument} from '@angular/fire/compat/firestore';
import { Observable } from 'rxjs';
import { tap, take,map} from 'rxjs/operators';
import { Product } from './Product';
@Injectable({
providedIn: 'root'
})
export class ProductService {
product$:any = {};
constructor(private db:AngularFireDatabase,public afs: AngularFirestore) {
}
create(product:any){
this.db.list('/products').push(product).then(()=>{console.log(`New product added with ID: ${product.id}`);});
this.afs.collection('/products').add(product).then(()=>{console.log(`New product added with ID: ${product.id}`);});
}
getAll(){
return this.afs.collection('/products');
}
getProductWithKey(id: string) {
return this.afs.doc<Product>(`/products/${id}`).snapshotChanges().pipe(
map(action => {
const data = action.payload.data() as Product;
const title = action.payload.data()?.title;
const price = action.payload.data()?.price;
const category = action.payload.data()?.category;
const imageUrl = action.payload.data()?.imageUrl;
console.log(action.payload.data()?.title);
const id = action.payload.id;
return { id,title,price,category,imageUrl};
})
);
}
}
我在控制台中得到的内容:
您传递给此方法的 id
getProductWithKey(id: string)
应该是 documentId
而不是文档字段中的自定义 id 字段。例如,您可以执行以下操作:
return this.afs.doc<Product>('/products/Fc8xq5nDMbIf0kZJY2AT').snapshotChanges().pipe(
map(action => {
这应该返回您在此列表中创建的第一个产品。或者另一种方式是获取集合中的所有文档,例如:
return this.afs.collection<any>('products').snapshotChanges().pipe(
map(actions => actions.map(a => a.payload.doc.data()))
);
}