0

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
  }

   
  }

 

Carlo A
  • 117
  • 9
  • Yeah, I did that but the updateTeller needs specific values coming from the filtered data, but all it can provide is the collectorBillNo which causes an error since it doesn't know which document is to be updated for. – Carlo A Jan 30 '22 at 07:48
  • You have tellerList object, now when you filter table, then get doc-id from tellerList object and pass this id to updateTeller function – GRD Jan 30 '22 at 07:54
  • add one more parameter to change function `(change)="loadBilling($any($event.target).value, tellerList)"` so, when select value changes then you have now tellerList also, and tellerList have your id like this `tellerList.id` . Confirm this way you get id or not. – GRD Jan 30 '22 at 08:01
  • Thank you for this however I'm still getting an error of undefined :< everytime i reload the form – Carlo A Jan 30 '22 at 23:22

1 Answers1

0

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 });
  }
}
Chris Hamilton
  • 9,252
  • 1
  • 9
  • 26
  • Thank you this work~ however do you know how to prevent the select tag from resetting? everytime I save the payment, it resets back to the first option. thank you. – Carlo A Jan 30 '22 at 23:22
  • It's most likely refreshing because you're changing the data, so your subscription is firing and changing `this.tellerList`, which causes the `select` element to refresh. I would put a `console.log("hi")` in your subscription to verify that it fires after the `savePayment()` method. If that's the case, you can get your selected index right before updating `tellerList`, then set it back to what it was after updating. You can probably use `ViewChild` with a template id to get the `HTMLSelectElement` and mess with it. – Chris Hamilton Jan 31 '22 at 03:35
  • Although a cleaner option would be to attach only the object id's to the option elements, since they won't change. The downside is you'll have to query the database for the teller's current `collectorBillNo` before you can increment it. – Chris Hamilton Jan 31 '22 at 03:41