简体   繁体   中英

Material table datasource storing data in filteredData property instead of data property

In my angular project, I have a table on a page that contains a list of bank accounts with their balance and other data etc (ref pic below). 银行名单表

My aim is to make table entries clickable so that every time someone clicks a row in the table, another component that contains bank transactions in a material table, Bank Ledger , opens in a dialog and shows record of the corresponding bank account, row of which has been clicked in the Bank Balance table.

To do that, I send account number to a function in service which pushes it to an observable subject. And the bank ledger component is subscribed to the aforementioned observable. Refer below code:

Component on which Bank Balance table is:

  constructor(private Fin:Finservice) {}

  acnum:number;

  viewBankLedger(): void {
    const dialogRef = this.dialog.open( BankledgerComponent , { width: '40vw', height: '80vh', disableClose: true, panelClass: "foo" } ); 
  }

  openLedger(row) {
    this.acnum = row.bank_acnum;
    this.Fin.getBankACNum(this.acnum);
    this.viewBankLedger();
  }

Fin Service:

  private _subject = new Subject<any>();
  changebank = this._subject.asObservable();

  getBankACNum(acnum: number){
    this._subject.next(acnum);
  }

Bank Ledger component:

export class BankledgerComponent implements OnInit {

  constructor(private Fin: Finservice, private LS: LedgerService) {}

  ngOnInit() {
    this.Fin.changebank.subscribe( result => {
      this.acnum = result;
      const bankACNum = {
        acnum: this.acnum,
      };
      this.getLedger(bankACNum);  
    })
  }
  
  BankLedgerDataSource = new MatTableDataSource<BankLedger>();
  bankLedger: BankLedger[];
  acnum:number;
  ledgerColumns: string[] = ['serial', 'bl_date', 'bl_part', 'bl_debit', 'bl_credit', 'bl_balance'];

  getLedger(bankACNum:ACNum){
    this.LS.showBankLedger(bankACNum).subscribe((results:BankLedger[])=>{
      this.bankLedger = results;
      this.BankLedgerDataSource.data = this.bankLedger;
      console.log(this.BankLedgerDataSource);
    })
  }

}

Bank Ledger template:

<div mat-dialog-content style="background-color: white; border-radius: 5px; padding: 1%;">

        <table style="width: 100%;" mat-table [dataSource]="BankLedgerDataSource" class="mat-elevation-z8">
            
        <ng-container matColumnDef="serial">
            <th mat-header-cell *matHeaderCellDef> S.No. </th>
            <td mat-cell *matCellDef="let element; let i = index;"> {{i+1}} </td>
        </ng-container>
                
        <ng-container matColumnDef="bl_date">
            <th mat-header-cell *matHeaderCellDef> Date </th>
            <td mat-cell *matCellDef="let element">{{element.bl_date | date:'dd/MM/yyyy'}} </td>
        </ng-container>
                
        <ng-container matColumnDef="bl_part">
            <th mat-header-cell *matHeaderCellDef> Particulars </th>
            <td mat-cell *matCellDef="let element"> {{element.bl_part}} </td>
        </ng-container>

        <ng-container matColumnDef="bl_debit">
            <th mat-header-cell *matHeaderCellDef> Debit Amount</th>
            <td mat-cell *matCellDef="let element"> {{element.bl_debit  | INRCurrency}} </td>
        </ng-container>

        <ng-container matColumnDef="bl_credit">
            <th mat-header-cell *matHeaderCellDef> Credit Amount</th>
            <td mat-cell *matCellDef="let element"> {{element.bl_credit  | INRCurrency}} </td>
        </ng-container>
            
        <ng-container matColumnDef="bl_balance">
            <th mat-header-cell *matHeaderCellDef> Balance </th>
            <td mat-cell *matCellDef="let element"> {{element.bl_balance  | CreditDebit}} </td>
        </ng-container>

        <tr mat-header-row *matHeaderRowDef="ledgerColumns"></tr>
        <tr class="tablerow" mat-row *matRowDef="let row; columns: ledgerColumns;"> </tr>

    </table>
La la la
</div>

<div mat-dialog-actions style="margin-top: 2%; border-top: 1px solid black;">
    <button type="button" class="btn btn-outline-dark" [mat-dialog-close]="true">Close</button>
</div>

As you can see above, have subscribed to the subject, created a json package and sent it to a method that retrieves corresponding data from the api using another service, called Ledger Service.

export class LedgerService {

  constructor(private httpClient: HttpClient) { }
  
showBankLedger(acnum: ACNum): Observable<BankLedger[]> {
    return this.httpClient.post<any>(`${this.PHP_API_SERVER}/apiroute.php`, acnum);
  }

While everything should work fine, I am facing multiple problems God kows why. Here are the problem I am facing:

  1. After the component that contains Bank Balance table loads for the first time; the first time I click any row, the dialog pops up but data does not seem to go through because there are no logs in the console.

  2. After I close the dialog, second click onward, data does seem to go to the Bank Ledger Component, but the table does not show any data. Also, data gets stored din the filteredData property of MatDataSource.

bankLedger 属性的控制台日志

BankLedgerDataSource 的控制台日志

  1. The results after are same 3rd click onward, but with an exception; after the 3rd click, console logs data 2 times instead of 1. In the 4th click, data is logged 3 times. And it continues so on and so forth.

对应点击的控制台日志

Please help. I am stumped.

I found the solution, albeit not a fancy one, but things work all the same.

As suggested by @tony, I tried using Change detector but to no avail. Didn't try *ngIf method subsequently suggested by him, because I knew it wouldn't work, at least the way I want it to. I do use async/await in my solution.

In my question I am using one component to send account number to a service. Then that service passes the data through an observable to another component and then that component again sends the same data to another different service to fetch required data from the api.

I circumvented that juggling to simply sending acnum to a service. Then getting the required data from the api in the service itself. From there it was easy. Just sent the array to another component, subscribed inside onInit and wallah, things started working like a charm. Updated code below:

Fin Component

  viewBankLedger(): void {
    const dialogRef = this.dialog.open( BankledgerComponent , { width: '40vw', height: '80vh', disableClose: true, panelClass: "foo" } ); 
  }

  openLedger(row) {
    this.acnum = row.bank_acnum;
    this.service.getBankACNum(this.acnum);
    this.viewBankLedger();
  }

Service

  private _subject = new Subject<any>();
  changebank =  this._subject.asObservable();
  sendBankLedger(result){
    this._subject.next(result);
  }
  
  async getBankACNum(acnum) { 
    const bankACNum = {
      acnum: acnum,
    };
    const data = await this.http.post<any>(`${this.PHP_API_SERVER}/api/fin/readbankledger.php`, bankACNum).toPromise();
    this.results = data;
    console.log(this.results);
    this.sendBankLedger(this.results);
  }
 

Bank Ledger Component (opens in dialog)

  ngOnInit() {
    this.service.changebank.subscribe(results=>{
      this.bankLedger = results;
      console.log(this.bankLedger);
      this.BankLedgerDataSource.data = this.bankLedger;
    });
  }
  
  BankLedgerDataSource = new MatTableDataSource<BankLedger>();
  bankLedger: BankLedger[];

This solution does not work without async/await. Hope someone finds it helpful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM