Search code examples
angulartypescriptangularfire

Updating a Firestore Collection from a filtered function


I have a firestore collection called Collectors and I'm interacting with it via angularfire. I'm able to subscribe and filtered from it to get the documents on it especially the collectorBillNo (please refer to the image), however, I'm stuck on the part where I need to increment the value of the collectorBillNo by 1 and update the document when I call a savePayment function.

enter image description here

Service Component:


import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument} from '@angular/fire/compat/firestore';
import { Observable } from 'rxjs';
import {map } from 'rxjs/operators';
import { teller } from '../models/tellermodel';

export class CustomerService {

  tellerCollections: AngularFirestoreCollection <teller>;
  tellerDoc: AngularFirestoreDocument <teller>;
  tellers: Observable<teller[]>;

  constructor(
    public angularFireStore: AngularFirestore

  ) 
  {}

  getTeller() {
    this.tellerCollections = this.angularFireStore.collection('collector');
    this.tellers = this.tellerCollections.snapshotChanges().pipe(map(changes => {
      return changes.map( a => {
        const data = a.payload.doc.data() as teller;
        data.id=a.payload.doc.id;
        return data;
      })

    }))
    return this.tellers

    updateTeller( updateCol: teller) {
    this.tellerDoc = this.angularFireStore.doc(`collector/${updateCol.id}`);
    this.tellerDoc.update(updateCol);
  }
}

HTML doing the filtering part

<div class="bill-heads">
        <label>Teller Name: </label>
        <select  class="select-drop" 
        required
        name="tellerName" 
        (change)="loadBilling($any($event.target).value)"
        id="collector" 
        [(ngModel)]="updateLedger.collectorName">
            <option 
            class ="teller-class"
            value="{{tellerList.collectorName}}"
            *ngFor ="let tellerList of tellerList"
            >
            {{tellerList.collectorName}}
            </option>
        </select>   
       </div>

Component ts

import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { CustomerService } from 'src/app/services/customer.service'; // Service Component
import { teller } from 'src/app/models/tellermodel'; // Model
import { MatTableDataSource } from '@angular/material/table';

@Component({
  selector: 'app-teller',
  templateUrl: './teller.component.html',
  styleUrls: ['./teller.component.scss']
})
export class TellerComponent implements OnInit {
    constructor(
    private customerService: CustomerService, // Calls the AngularFire Service
  ) { }
  // Declarations goes Here
  tellerList: teller[]; // loads the collection as observable
  dataTellerSource: MatTableDataSource<any>; // for filtering
  billNo: any; // this is where the collectorBillNo will be stored upon filtering

  ngOnInit(): void {
  //Subscribe to the collection
   this.customerService.getTeller().subscribe(telObs => {
      this.tellerList = telObs; // Subsribes as an Observable
      this.dataTellerSource = new MatTableDataSource(telObs); // loads the observable as DataSource
    }) 

loadBilling(collector:string) { // performs the filter from the HTML method
    // using MatTableDatesource filter, I can able to filter the specific document,
    get its collectorBillNo
    this.collectorName = collector;
    this.dataTellerSource.filter = collector.trim().toLowerCase();
    this.billNo = this.dataTellerSource.filteredData
    .map (bn => bn.collectorBillNo)
    .reduce ((acc,cur) => acc+cur,0); // this gets the collectBillNo

  savePayment() // it should update the document and increment the collectorCode by 1
    this.billNo = this.billNo + 1
 
 /// I don't know what to do next here for it to be able to save from its respective document
  }

   
  }

 


Solution

  • Bind the entire object to each option in the HTML, using ngValue. The selected object will be attached to the ngModel variable of the select element.

    It seems you bound ngModel to updateLedger.collectorName which I don't see in the component, so I'll make a new variable called selectedTeller.

    <div class="bill-heads">
            <label>Teller Name: </label>
            <select  class="select-drop" 
            required
            name="tellerName"
            id="collector" 
            [(ngModel)]="selectedTeller">
                <option 
                class ="teller-class"
                *ngFor ="let teller of tellerList"
                [ngValue]="teller"
                >
                {{teller.collectorName}}
                </option>
            </select>   
    </div>
    

    Notice I've removed the (change) event, since angular will update the selected object automatically.

    So your component will look like this

    import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
    import { CustomerService } from 'src/app/services/customer.service'; // Service Component
    import { teller } from 'src/app/models/tellermodel'; // Model
    import { MatTableDataSource } from '@angular/material/table';
    
    @Component({
      selector: 'app-teller',
      templateUrl: './teller.component.html',
      styleUrls: ['./teller.component.scss']
    })
    export class TellerComponent implements OnInit {
        constructor(
        private customerService: CustomerService, // Calls the AngularFire Service
      ) { }
      // Declarations goes Here
      tellerList: teller[]; // loads the collection as observable
      dataTellerSource: MatTableDataSource<any>; // for filtering
      billNo: any; // this is where the collectorBillNo will be stored upon filtering
      selectedTeller: teller;
    
      ngOnInit(): void {
      //Subscribe to the collection
       this.customerService.getTeller().subscribe(telObs => {
          this.tellerList = telObs; // Subsribes as an Observable
          this.dataTellerSource = new MatTableDataSource(telObs); // loads the observable as DataSource
        }) 
    
      savePayment() {
        this.customerService.updateTeller({ ...this.selectedTeller, collectorBillNo: this.selectedTeller.collectorBillNo + 1 });
      }
    }