如何从 firestore 检索数据并将其填写到表单中进行编辑(角度)

问题描述 投票:0回答:1

在我基于 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};
    })
  );
}
}

list of products got from firestore databse expected when click id got only id in the form !

我在控制台中得到的内容:

javascript angular firebase google-cloud-firestore
1个回答
0
投票

您传递给此方法的 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()))
     );
  }
© www.soinside.com 2019 - 2024. All rights reserved.