【问题标题】:Two way databiding not working properly (Angular 13)两种方式数据绑定无法正常工作(Angular 13)
【发布时间】:2022-02-05 02:26:11
【问题描述】:

我使用的是 Angular 13.1.2,这是我的 package.json 和我的。

angular.json:

    {
      "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
      "cli": {
      "analytics": false
       },
       "version": 1,
       "newProjectRoot": "projects",
       "projects": {
         "Sefaz.Responsaveis.Client": {
           "projectType": "application",
           "schematics": {
             "@schematics/angular:component": {
               "style": "scss"
             },
             "@schematics/angular:application": {
               "strict": true
             }
           },
           "root": "",
           "sourceRoot": "src",
           "prefix": "app",
           "architect": {
             "build": {
               "builder": "@angular-devkit/build-angular:browser",
               "options": {
                 "outputPath": "dist",
                 "index": "src/index.html",
                 "main": "src/main.ts",
                 "polyfills": "src/polyfills.ts",
                 "tsConfig": "tsconfig.app.json",
                 "inlineStyleLanguage": "scss",
                 "assets": [
                   "src/favicon.ico",
                   "src/assets"
                 ],
                 "styles": [
                   "./node_modules/bootstrap/dist/css/bootstrap.min.css",
                   "./node_modules/bootstrap-icons/font/bootstrap-icons.css",
                   "./node_modules/ngx-toastr/toastr.css",
                   "node_modules/primeicons/primeicons.css",
                   "node_modules/primeng/resources/themes/saga-blue/theme.css",
                   "node_modules/primeng/resources/primeng.min.css",
                   "src/styles.scss"
                 ],
                 "scripts": []
               },
               "configurations": {
                 "production": {
                   "budgets": [
                     {
                       "type": "initial",
                       "maximumWarning": "500kb",
                       "maximumError": "2mb"
                     },
                     {
                       "type": "anyComponentStyle",
                       "maximumWarning": "2kb",
                       "maximumError": "4kb"
                     }
                   ],
                   "fileReplacements": [
                     {
                       "replace": "src/environments/environment.ts",
                       "with": "src/environments/environment.prod.ts"
                     }
                   ],
                   "outputHashing": "all",
                   "optimization": {
                     "scripts": true,
                     "styles": true,
                     "fonts": false
                   }
                 },
                 "development": {
                   "buildOptimizer": false,
                   "optimization": false,
                   "vendorChunk": true,
                   "extractLicenses": false,
                   "sourceMap": true,
                   "namedChunks": true
                 }
               },
               "defaultConfiguration": "production"
             },
             "serve": {
               "builder": "@angular-devkit/build-angular:dev-server",
               "configurations": {
                 "production": {
                   "browserTarget": "Sefaz.Responsaveis.Client:build:production"
            },
            "development": {
              "browserTarget": "Sefaz.Responsaveis.Client:build:development"
            }
          },
          "defaultConfiguration": "development"
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "Sefaz.Responsaveis.Client:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "inlineStyleLanguage": "scss",
            "assets": [              
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "./node_modules/bootstrap/dist/css/bootstrap.min.css",
              "./node_modules/bootstrap-icons/font/bootstrap-icons.css",
              "src/styles.scss"
            ],
            "scripts": []
          }
        }
      }
    }
  },
  "defaultProject": "Sefaz.Responsaveis.Client"
    }

package.json:

    {
      "name": "sefaz.responsaveis.client",
      "version": "0.0.0",
      "scripts": {
        "ng": "ng",
        "start": "ng serve --verbose",
        "build": "ng build",
        "build:ssr": "ng run Sefaz.Responsaveis.Client:server:dev",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      },
      "private": true,
      "dependencies": {
        "@angular-devkit/schematics": "^13.1.4",
        "@angular/animations": "~13.1.2",
        "@angular/cdk": "^13.1.2",
        "@angular/common": "~13.1.2",
        "@angular/compiler": "~13.1.2",
        "@angular/core": "~13.1.2",
        "@angular/forms": "~13.1.2",
        "@angular/localize": "~13.1.2",
        "@angular/material": "^13.1.2",
        "@angular/platform-browser": "~13.1.2",
        "@angular/platform-browser-dynamic": "~13.1.2",
        "@angular/platform-server": "^13.1.2",
        "@angular/router": "~13.1.2",
        "@ng-bootstrap/ng-bootstrap": "^10.0.0",
        "@nguniversal/module-map-ngfactory-loader": "^8.2.6",
        "@types/crypto-js": "^4.0.2",
        "bootstrap": "^4.5.0",
        "bootstrap-icons": "^1.5.0",
        "crypto-js": "^4.1.1",
        "file-saver": "^2.0.5",
        "moment": "^2.29.1",
        "ng-block-ui": "^3.0.2",
        "ngx-toastr": "^14.2.1",
        "primeicons": "^5.0.0",
        "primeng": "^13.1.0",
        "rxjs": "~6.6.0",
        "tslib": "^2.3.0",
        "zone.js": "~0.11.4"
      },
      "devDependencies": {
        "@angular-devkit/build-angular": "~13.1.3",
        "@angular/cli": "~13.1.3",
        "@angular/compiler-cli": "~13.1.2",
        "@angular/language-service": "^8.2.12",
        "@types/file-saver": "^2.0.4",
        "@types/jasmine": "~3.8.0",
        "@types/jasminewd2": "~2.0.8",
        "@types/node": "^12.11.1",
        "jasmine-core": "~3.8.0",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "~6.3.0",
        "karma-chrome-launcher": "~3.1.0",
        "karma-coverage": "~2.0.3",
        "karma-coverage-istanbul-reporter": "~2.1.0",
        "karma-jasmine": "~4.0.0",
        "karma-jasmine-html-reporter": "~1.7.0",
        "typescript": "~4.5.4"
      },
      "optionalDependencies": {
        "node-sass": "^4.12.0",
        "protractor": "~5.4.2",
        "ts-node": "~8.4.1",
        "tslint": "~5.20.0"
      }
    }

问题是我的表格组件上有一个双向数据绑定来设置选择属性,但是当我从表格组件中选择一个或多个项目时,在我的父组件中不显示该值:

父亲:

@Component({
  selector: 'app-oferta-compra',
  templateUrl: './oferta-compra.component.html',
  styleUrls: ['./oferta-compra.component.scss']
})
export class OfertaCompraComponent implements OnInit {
  pesquisaAutoridadeNegociacaoForm = this.fb.group({});
  pesquisaAgenteContratacaoForm = this.fb.group({});
  responsaveisColumns: Column<any>[] = [];
  responsaveisActions: Action<any>[] = [];
  autoridadeNegociacaoColumns: Column<any>[] = [];
  autoridadesNegociacao: any[] = [];
  autoridadesNegociacaoSelecionados: any[] = [];
  autoridadesNegociacaoSelecao: any[] = [];
  agenteContratacaoColumns: Column<any>[] = [];
  agentesContratacao: any[] = [];
  agentesContratacaoSelecionados: any[] = [];
  agentesContratacaoSelecao: any[] = [];
  mostrarModalAutoridadeNegociacao = false;
  mostrarModalAgenteContratacao = false;

  ...

  inicializarTabelas(): void {
    this.responsaveisColumns = [
      {
        header: 'CPF',
        field: 'cpf',
        matColumnDef: 'cpf'
      },
      {
        header: 'Nome',
        field: 'nome',
        matColumnDef: 'nome'
      },
      {
        header: 'Telefone',
        field: 'telefone',
        matColumnDef: 'telefone'
      },
      {
        header: 'E-mail',
        field: 'email',
        matColumnDef: 'email'
      }
    ];

    this.responsaveisActions = [
      {
        icon: 'edit'
      }
    ];

    this.autoridadeNegociacaoColumns = [
      {
        header: 'CPF',
        field: 'cpf',
        matColumnDef: 'cpf'
      },
      {
        header: 'Nome',
        field: 'nome',
        matColumnDef: 'nome'
      },
      {
        header: 'Telefone',
        field: 'telefone',
        matColumnDef: 'telefone'
      },
      {
        header: 'Ramal',
        field: 'ramal',
        matColumnDef: 'ramal'
      },
      {
        header: 'E-mail',
        field: 'email',
        matColumnDef: 'email'
      }
    ];

    this.agenteContratacaoColumns = [
      {
        header: 'CPF',
        field: 'cpf',
        matColumnDef: 'cpf'
      },
      {
        header: 'Nome',
        field: 'nome',
        matColumnDef: 'nome'
      },
      {
        header: 'Telefone',
        field: 'telefone',
        matColumnDef: 'telefone'
      },
      {
        header: 'Ramal',
        field: 'ramal',
        matColumnDef: 'ramal'
      },
      {
        header: 'E-mail',
        field: 'email',
        matColumnDef: 'email'
      }
    ];
  }

  ...

  selecionarAutoridadeNegociacao(): void {
    this.autoridadesNegociacaoSelecionados = [...this.autoridadesNegociacaoSelecao];
    this.mostrarModalAutoridadeNegociacao = false;
  }

  selecionarAgenteContratacao(): void {
    this.agentesContratacaoSelecionados = [...this.agentesContratacaoSelecao];
    this.mostrarModalAgenteContratacao = false;
   }
}

父亲html:

 <div class="row mb-3">
                        <div class="col-sm-12">
                            <h3>Responsáveis Definidos para Está Oferta de Compra</h3>
                        </div>
                        <div class="col-sm-4">
                            <button mat-button style="width: 100%;" type="button" color="primary"
                                (click)="mostrarModalAutoridadeNegociacao = true"
                                class="botao-autoridade-negociação d-flex align-items-center justify-content-center">
                                <mat-icon>add</mat-icon>
                                Selecionar Autoridade de Negociação
                            </button>
                        </div>
                    </div>
                    <div class="row mb-5">
                        <div *ngIf="autoridadesNegociacaoSelecionados.length > 0" class="col-sm-12">
                            <app-table [data]="autoridadesNegociacaoSelecionados"
                                [columns]="responsaveisColumns" [actions]="responsaveisActions"
                                [length]="autoridadesNegociacaoSelecionados.length"></app-table>
                        </div>
                        <div *ngIf="autoridadesNegociacaoSelecionados.length === 0" class="col-sm-12">
                            <p>Nenhum Responsável Definido para esse Perfil</p>
                        </div>
                    </div>
                    <div class="row mb-3">
                        <div class="col-sm-4">
                            <button mat-button style="width: 100%;" type="button" color="primary"
                                (click)="mostrarModalAgenteContratacao = true"
                                class="botao-autoridade-negociação d-flex align-items-center justify-content-center">
                                <mat-icon>add</mat-icon>
                                Selecionar Agente de Contratação
                            </button>
                        </div>
                    </div>
                    <div class="row">
                        <div *ngIf="agentesContratacaoSelecionados.length > 0" class="col-sm-12">
                            <app-table [data]="agentesContratacaoSelecionados" [columns]="responsaveisColumns"
                                [actions]="responsaveisActions" [length]="agentesContratacaoSelecionados.length">
                            </app-table>
                        </div>
                        <div *ngIf="agentesContratacaoSelecionados.length === 0" class="col-sm-12">
                            <p>Nenhum Responsável Definido para esse Perfil</p>
                        </div>
                    </div>
<p-dialog header="Autoridade de Negociação" [(visible)]="mostrarModalAutoridadeNegociacao" [style]="{width: '70vw'}">
    <div class="p-3">
        <form (ngSubmit)="pesquisarAutoridadeNegociacao()" [formGroup]="pesquisaAutoridadeNegociacaoForm"
            #form="ngForm">
            <div class="row d-flex align-items-center justify-content-start">
                <div class="col-sm-4">
                    <app-input identifier="PesquisarCpfNome1" label="Pesquisar por CPF ou Nome" [required]="false"
                        [parentForm]="pesquisaAutoridadeNegociacaoForm" [ngForm]="form">
                    </app-input>
                </div>
                <div class="col-sm-3">
                    <button mat-button style="width: 100%;" type="button" color="primary"
                        class="botao-pesquisar-autoridade-negociacao d-flex align-items-center justify-content-center">
                        <mat-icon>search</mat-icon>
                        Pesquisar
                    </button>
                </div>
            </div>
        </form>
        <div class="row">
            <div class="col-sm-12">
                <app-table [data]="autoridadesNegociacao" [columns]="autoridadeNegociacaoColumns"
                    [(selecionados)]="autoridadesNegociacaoSelecao" [length]="autoridadesNegociacao.length"
                    selectionMode="checkbox" [selectHeaderWithCheckbox]="false">
                </app-table>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-sm-6"></div>
            <div class="col-sm-3">
                <button mat-button style="width: 100%;" type="button" color="primary"
                    (click)="mostrarModalAutoridadeNegociacao = false"
                    class="botao-fechar-autoridade-negociacao d-flex align-items-center justify-content-center">
                    <mat-icon>close</mat-icon>
                    Fechar
                </button>
            </div>
            <div class="col-sm-3">
                <button mat-button style="width: 100%;" type="button" color="primary"
                    (click)="selecionarAutoridadeNegociacao()"
                    class="botao-confirmar-autoridade-negociacao d-flex align-items-center justify-content-center">
                    <mat-icon>done</mat-icon>
                    Confirmar
                </button>
            </div>
        </div>
    </div>
</p-dialog>

<p-dialog header="Agente de Contratação" [(visible)]="mostrarModalAgenteContratacao" [style]="{width: '70vw'}">
    <div class="p-3">
        <form (ngSubmit)="pesquisarAgenteContratacao()" [formGroup]="pesquisaAgenteContratacaoForm" #form2="ngForm">
            <div class="row d-flex align-items-center justify-content-start">
                <div class="col-sm-4">
                    <app-input identifier="PesquisarCpfNome2" label="Pesquisar por CPF ou Nome" [required]="false"
                        [parentForm]="pesquisaAgenteContratacaoForm" [ngForm]="form2">
                    </app-input>
                </div>
                <div class="col-sm-3">
                    <button mat-button style="width: 100%;" type="button" color="primary"
                        class="botao-pesquisar-autoridade-negociacao d-flex align-items-center justify-content-center">
                        <mat-icon>search</mat-icon>
                        Pesquisar
                    </button>
                </div>
            </div>
        </form>
        <div class="row">
            <div class="col-sm-12">
                <app-table [data]="agentesContratacao" [columns]="agenteContratacaoColumns"
                    [(selecionados)]="agentesContratacaoSelecao" [length]="agentesContratacao.length"
                    selectionMode="checkbox" [selectHeaderWithCheckbox]="false">
                </app-table>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-sm-6"></div>
            <div class="col-sm-3">
                <button mat-button style="width: 100%;" type="button" color="primary"
                    (click)="mostrarModalAgenteContratacao = false"
                    class="botao-fechar-autoridade-negociacao d-flex align-items-center justify-content-center">
                    <mat-icon>close</mat-icon>
                    Fechar
                </button>
            </div>
            <div class="col-sm-3">
                <button mat-button style="width: 100%;" type="button" color="primary"
                    (click)="selecionarAgenteContratacao()"
                    class="botao-confirmar-autoridade-negociacao d-flex align-items-center justify-content-center">
                    <mat-icon>done</mat-icon>
                    Confirmar
                </button>
            </div>
        </div>
    </div>
</p-dialog>

子 ts:

@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit {

  @Input() data: any[] = [];
  @Input() columns: Column<any>[] = [];
  @Input() actions: Action<any>[] = [];
  @Input() length = -1;
  @Input() pageSize = 10;
  @Input() pageSizeOptions = [5, 10, 20, 50, 100];
  @Input() paginator = false;
  @Input() lazyLoading = false;
  @Input() selectionMode: 'checkbox' | '' = '';
  @Input() selectHeaderWithCheckbox = false;

  _selecionados: any[] = [];
  @Input() get selecionados() { return this._selecionados; }
  @Output() selecionadosChange = new EventEmitter<any[]>();
  set selecionados(selecionados: any[]) {
    if (this._selecionados !== selecionados) {
      this._selecionados = selecionados;
      this.selecionadosChange.emit(selecionados);
    }
  }

  @Output() page = new EventEmitter<PageEvent>();

  dataSource = new MatTableDataSource<any>();
  dataSourcePaginacao = new MatTableDataSource<any>();
  displayedColumns: string[] = [];
  selection = new SelectionModel<any>(true, []);

  constructor() { }

  ngOnInit(): void {
    if (this.selectionMode === 'checkbox')
      this.displayedColumns.push('select');
    this.columns.forEach(c => {
      this.displayedColumns.push(c.matColumnDef);
    });
    if (this.actions && this.actions.length > 0) {
      let count = 0;
      this.actions.forEach(a => {
        this.displayedColumns.push('actions_' + count);
        count++;
      })
    }
    this.dataSource.data = [...this.data];
    this.dataSourcePaginacao.data = [...this.data];
    this.selection.select(...this._selecionados);
  }

  onPage(pageEvent: PageEvent): void {
    if (this.lazyLoading)
      this.page.emit(pageEvent);

    this.dataSource.data = [...this.dataSourcePaginacao.data].slice(pageEvent.pageIndex * pageEvent.pageSize, (pageEvent.pageIndex * pageEvent.pageSize) + pageEvent.pageSize);
  }

  displayValue(col: Column<any>, obj: any): string | null {
    if (col.valueDisplayFn) {
      return col.valueDisplayFn(obj);
    }

    if (col.field) {
      return obj[col.field];
    }

    return null;
  }

  isAllSelected() {
    const numSelected = this.selection?.selected?.length;
    const numRows = this.dataSource?.data?.length;
    return numSelected === numRows;
  }

  masterToggle() {
    if (this.isAllSelected()) {
      this.selection.clear();
      return;
    }

    this.selection.select(...this.dataSource.data);
    this.selecionados = [...this.selection.selected];
  }

  toggle(row: any): void {
    this.selection.toggle(row);
    this._selecionados = [...this.selection.selected];
  }
}

子 html:

<div class="table-responsive">
    <mat-table #table [dataSource]="dataSource" class="mat-elevation-z8">
        <ng-container *ngIf="selectionMode == 'checkbox'" matColumnDef="select">
            <mat-header-cell *matHeaderCellDef>
                <mat-checkbox *ngIf="selectHeaderWithCheckbox" (change)="$event ? masterToggle() : null"
                    [checked]="selection.hasValue() && isAllSelected()"
                    [indeterminate]="selection.hasValue() && !isAllSelected()">
                </mat-checkbox>
            </mat-header-cell>
            <mat-cell *matCellDef="let row">
                <mat-checkbox (click)="$event.stopPropagation()" (change)="toggle(row)"
                    [checked]="selection.isSelected(row)">
                </mat-checkbox>
            </mat-cell>
        </ng-container>
        <ng-container *ngFor="let col of columns" [matColumnDef]="col.matColumnDef">
            <mat-header-cell *matHeaderCellDef>{{col.header}}</mat-header-cell>
            <mat-cell *matCellDef="let obj">
                <span>{{displayValue(col, obj)}}</span>
            </mat-cell>
        </ng-container>
        <ng-container *ngIf="actions && actions.length > 0">
            <ng-container *ngFor="let action of actions; let i = index" [matColumnDef]="'actions_' + i">
                <mat-header-cell *matHeaderCellDef>{{action.header}}</mat-header-cell>
                <mat-cell *matCellDef="let obj">
                    <button mat-icon-button type="button" color="primary" (click)="action.handler(obj, index)"
                        class="d-flex align-items-center justify-content-center">
                        <mat-icon>{{action.icon}}</mat-icon>
                        {{action.text}}
                    </button>
                </mat-cell>
            </ng-container>
        </ng-container>

        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="toggle(row)"></mat-row>
    </mat-table>
    <mat-paginator *ngIf="paginator" [length]="length" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
        (page)="onPage($event)">
    </mat-paginator>
</div>
<code>{{selecionados | json}}</code>

【问题讨论】:

  • 我忘了,没有设置的属性是“autoridadesNegociacaoSelecao”。

标签: javascript html angular


【解决方案1】:

好吧,我不知道原因,但对我有用的是删除“...”并改用 foreach:

toggle(row: any): void {
    this.selection.toggle(row);
    const tamanho = this._selecionados.length;
    for (let index = 0; index < tamanho; index++) {
      this._selecionados.splice(0, 1);
    }
    this.selection.selected.forEach(s => {
      this._selecionados.push({...s});
    });
}

selecionarAutoridadeNegociacao(): void {
    this.autoridadesNegociacaoSelecionados = [];
    this.autoridadesNegociacaoSelecao.forEach(ans => {
      this.autoridadesNegociacaoSelecionados.push(ans);
    });
    this.mostrarModalAutoridadeNegociacao = false;
}

selecionarAgenteContratacao(): void {
    this.agentesContratacaoSelecionados = [];
    this.agentesContratacaoSelecao.forEach(acs => {
      this.agentesContratacaoSelecionados.push(acs);
    });
    this.mostrarModalAgenteContratacao = false;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多