首页 > 解决方案 > 如何从双向绑定表单输入控件访问先前的值?

问题描述

鉴于此处的表格,我希望能够更新 SQL 表中的数据。为了创建实现这一点所需的 SQL 查询,我必须同时传递前一行的值和新行的值以进行正确的比较。

示例 SQL 更新语句:

UPDATE MyTable 
SET column1 = new_value1, column2 = new_value2, 
WHERE column1 = oldValue1 AND column2 = oldValue2

但是,由于我的输入使用双向绑定,因此在尝试将其传递给我的 SQL 服务时,我总是会得到新值。有没有办法在发送它进行更新之前访问该行的先前值?

表单 HTML:

  <form #updateRowForm="ngForm" class="update-row-form">
            <table mdbTable #tableEl="mdbTable" class="table table-bordered
              table-responsive-md table-striped text-center">
              <thead>
                <tr>
                  <th *ngFor="let head of loadedTableData[0] | keys;">{{head}}</th>
                </tr>
              </thead>
              <tbody>
                <tr *ngFor="let item of loadedTableData; let i = index;">
                  <td *ngFor="let property of item | keys;"
                    class="form-group" #editRow>
                    <input #editRowProp mdbInput
                      [(ngModel)]="loadedTableData[i][property]"
                      (click)="updateValue(item)"
                      (ngModelChange)="changeValue($event, item)"
                      class="form-control"
                      [name]="property + '_' + i"
                      type="text">
                  </td>
                  <td>
                    <button type="button" mdbBtn class="btn btn-primary
                      rounded
                      btn-sm my-0"
                      (click)="updateRow(loadedTableData[i], item)">Update</button>
                    <hr>
                    <button type="button" mdbBtn class="btn btn-danger
                      rounded
                      btn-sm my-0" (click)="deleteRow(item)">Remove</button>
                  </td>
                </tr>
              </tbody>
            </table>
          </form>

组件 TS 文件:

import { Component, OnInit, ViewChild, ViewChildren, QueryList, OnDestroy } from 
'@angular/core';
import { SqlService } from '../services/sql.service';
import { MdbTablePaginationComponent, MdbTableDirective } from 'angular-bootstrap-md';
import { NgForm, FormGroup } from '@angular/forms';
import { Subscription, BehaviorSubject } from 'rxjs';
import { MatSnackBar } from '@angular/material';
import { SuccessComponent } from '../snackbar/success/success.component';
import { ErrorComponent } from '../snackbar/error/error.component';
import { ConfirmComponent } from '../snackbar/confirm/confirm.component';

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.scss']
})
export class DataTableComponent implements OnInit, OnDestroy {
  @ViewChild(MdbTablePaginationComponent) mdbTablePagination: 
  MdbTablePaginationComponent;
  @ViewChild(MdbTableDirective) mdbTable: MdbTableDirective;
  @ViewChild('addRowForm') addRowForm: NgForm;
  @ViewChildren('prop') addRowProps: QueryList<any>;
  @ViewChild('editRowForm') editRowForm: NgForm;
  @ViewChild('editRow') editRow: FormGroup;

  public loadedTableData: any = [];
  public previousTableData: any = [];
  public displayedColumns: any = [];
  public tableHasBeenLoaded = false;
  public rowBeingEdited: BehaviorSubject<any> = new BehaviorSubject<any>({});
  public rowPreviousValue: BehaviorSubject<any> = new BehaviorSubject<any>({});
  public currentTableData: any = {};
  public rowsAffected = 0;

  public elements: string[] = [];
  public previous: any;

  private subscriptions: Subscription[] = [];

  constructor(private sqlService: SqlService,
              private snackBar: MatSnackBar) { }

  public ngOnInit(): void {
    this.subscriptions.push(
      this.sqlService.tableHasBeenLoaded.subscribe(data => {
        this.tableHasBeenLoaded = data;
      }),

  this.sqlService.tableHasBeenLoaded.subscribe(data => {
       this.tableHasBeenLoaded = data;
  }),

  this.sqlService.currentTableData.subscribe(data => {
    this.currentTableData = data;
  }),

  this.sqlService.rowsAffected.subscribe(data => {
    this.rowsAffected = data;
      })
    );
  }

  public updateRow(newRowValue: any, previousRowValue: any): void {

    // Both of these values are the same.
    console.log(newRowValue, ' << initialRow');
    console.log(previousRowValue, ' <<previousRowVal')



    const updateData = {
      previousRowValue,
      newRowValue
    };

    this.subscriptions.push(
      this.sqlService.updateTableData(updateData)
        .subscribe((resp) => {
        console.log(resp, ' << update response');
        // this.sqlService.currentDataView.next(resp);
        if (resp) {
          this.snackBar.openFromComponent(ConfirmComponent, {
            duration: 3000,
            data: this.rowsAffected
          });
        }
      })
     );

  }

  public ngOnDestroy(): void {
    for (const sub of this.subscriptions) {
      sub.unsubscribe();
    }
  }

}

SQL 服务 TS:

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders } from '@angular/common/http';
    import { tap } from 'rxjs/operators';
    import { Observable, BehaviorSubject } from 'rxjs';
    import { ITableList } from '../interfaces/ITableList.interface';

    @Injectable({
    providedIn: 'root'
    })
    export class SqlService {

    private uri = 'http://localhost:8080';
    private headers = new HttpHeaders({ 'Content-Type': 'application/json; charset=utf-8' });

    public currentDataView: BehaviorSubject<any> = new BehaviorSubject<any>([]);
    public currentTableData: BehaviorSubject<any> = new BehaviorSubject<any>({});
    public tableHasBeenLoaded: BehaviorSubject<any> = new BehaviorSubject<boolean>(false);
    public rowsAffected: BehaviorSubject<number> = new BehaviorSubject<number>(0);

    constructor(private http: HttpClient) { }

    public updateTableData(updateData: any): Observable<any> {
        const parsedData = JSON.parse(JSON.stringify(updateData));

        if (updateData) {
        return this.http.post(`${this.uri}/api/updateTableData`, parsedData).pipe(
            tap(
            response => {
                this.rowsAffected.next(response.rowsAffected);
            },
            error => {
                throw new Error(error);
            }
            )
        );
        }
    }

  }

标签: javascriptsqlangulartypescripttwo-way-binding

解决方案


嗨,再创建一个对象(例如 prevValue)在其中存储值。应该是深拷贝而不是浅拷贝。使用 JSON.stringify 和 JSON.parse 在对象中复制值。例如,在 newValue 对象中,您存储新值,在分配新值之前,将 newValue 保存在 prevValue 中,这样您将拥有 prevValue,就像您想要第一个值而不是不更新 preValue


推荐阅读