简体   繁体   English

选中子复选框时向父组件发送 id 值

[英]Sending id value to parent component when child check box is checked

In my angular 11 app, I have multiple components that each display a modal ( parent component ) that displays multiple components ( child component ) called FileInfo and has a button called "save" and another to close the modal I added a check box to each of the components, I want to send the fileId to the parent component when a check box is checked and the button "save" is clicked ( only one file can be checked ), the idea is the user will check a file from a modal and check another file form another modal and both fileIds will be sent to the other component that calls an API endpoint which takes two ids in parameter to compare the two files.在我的 angular 11 应用程序中,我有多个组件,每个组件都显示一个模式(父组件),该组件显示多个名为FileInfo的组件(子组件),并有一个名为“保存”的按钮和另一个用于关闭模式的按钮,我为每个组件添加了一个复选框在组件中,我想在选中复选框并单击“保存”按钮(只能检查一个文件)时将fileId发送到父组件,想法是用户将从模式中检查文件并从另一个模态检查另一个文件,两个fileIds将被发送到调用 API 端点的另一个组件,该端点在参数中使用两个 id 来比较两个文件。

I managed to display the fileId when a file box is checked on an open modal and store it in the array where I planned to keep the fileIds but when I switched to another modal and checked another file the array got overwritten.当在打开的模式上检查文件框时,我设法显示fileId并将其存储在我计划保留fileIds的数组中,但是当我切换到另一个模式并检查另一个文件时,数组被覆盖。

How do I fix that, and is there a better way to implement something like this?我该如何解决这个问题,有没有更好的方法来实现这样的事情?

Here is the code I used:这是我使用的代码:

file-info.component.ts文件信息.component.ts

@Component({
  selector: 'app-file-info',
  templateUrl: './file-info.component.html',
  styleUrls: ['./file-info.component.scss'],
})
export class FileInfoComponent implements OnInit {
  faFileCsv = faFileCsv;
  faTrash = faTrash;
  faFileDownload = faFileDownload;
  selectedFiles: any[] = [];
  @Output()
  public myOutput = new EventEmitter<any>();
  @Input() fileInfo: {
    _id: string;
    fileName: string;
    createdAt: string;
    NumberRecords: string;
  };
  constructor() {}

  ngOnInit(): void {}

  public handleClick(_id: string): void {
    this.myOutput.emit(this.fileInfo._id);
  }
  saveedFiles() {}
  check(e) {
    //console.log(e);
    //console.log(e.target.checked);
    this.selectedFiles.push(e.target.value);
    console.log(this.selectedFiles);
  }
}

file-info.component.html文件信息.component.html

<div class="card files EqualHeightCard">
  <div class="card-content">
    <div class="columns">
      <input
        (change)="check($event)"
        name="fileId"
        value="{{ fileInfo._id }}"
        type="checkbox"
      />
      <div class="column is-2 forImg">
        <fa-icon [icon]="faFileCsv" size="4x"></fa-icon>
      </div>
      <div class="column forInfos">
        <p class="SourceName">File Name : {{ fileInfo.fileName }}</p>
        <p class="SourceDesc mt-2">
          Number of records : {{ fileInfo.NumberRecords }}
        </p>
      </div>
      <div class="column forInfos">
        <p class="SourceName">Loading date : {{ fileInfo.createdAt }}</p>
      </div>

      <div class="buttons">
        <div class="ml-4">
          <fa-icon [icon]="faFileDownload" size="2x"></fa-icon>
        </div>
        <div class="ml-4">
          <fa-icon
            [icon]="faTrash"
            size="2x"
            (click)="handleClick($event)"
          ></fa-icon>
        </div>
      </div>
    </div>
  </div>
</div>
<br />

modal.component.html modal.component.html

<div class="centered-content">
  <div class="modal is-active">
    <div class="modal-background"></div>
    <div class="modal-card">
      <header class="modal-card-head">
        <p class="modal-card-title">{{ sourceName }} uploaded files history</p>
      </header>
      <section class="modal-card-body">
        <app-file-info
          *ngFor="let fileInfo of FileInfoList"
          [fileInfo]="fileInfo"
          (myOutput)="parentHandleClick($event)"
        ></app-file-info>
        <p>Number of files : {{ FileInfoList.length }}</p>
      </section>
      <footer class="modal-card-foot">
        <div class="buttons is-right">
          <button class="button is-success">Save changes</button>
          <button
            class="button is-danger is-outlined"
            aria-label="close"
            (click)="cancel()"
          >
            <span>Close</span>
            <span class="icon is-small">
              <fa-icon [icon]="faTimes"></fa-icon>
            </span>
          </button>
        </div>
      </footer>
    </div>
  </div>
</div>

modal.component.ts modal.component.ts

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.scss'],
})
export class ModalComponent implements OnInit {
  faFileCsv = faFileCsv;
  faTimes = faTimes;
  FileInfoList: any = [];
  @Input() sourceId: { _id: string };
  @Input() sourceName: { name: string };
  constructor(private readonly _crudService: CrudService) {}

  ngOnInit(): void {
    /*  this._crudService.GetFileInfoList().subscribe((res) => {
      this.FileInfoList = res;
    }); */
    this._crudService.GetALLFilesOfSource(this.sourceId).subscribe((res) => {
      this.FileInfoList = res;
    });
  }
  @Output()
  onClose = new EventEmitter();
  cancel() {
    this.onClose.emit(null);
  }
  parentHandleClick($event) {
    return this._crudService
      .DeleteFileOfSource(this.sourceId, $event)
      .subscribe((res) => {
        this.FileInfoList = res;
      });
  }
}

crud.service.ts crud.service.ts

import { Injectable } from '@angular/core';
import { catchError, map } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
import {
  HttpClient,
  HttpHeaders,
  HttpErrorResponse,
} from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class CrudService {
  // Node/Express API
  REST_API: string = 'http://localhost:4000';
  // Http Header
  httpHeaders = new HttpHeaders().set('Content-Type', 'application/json');
  constructor(private httpClient: HttpClient) {}

  // Get all objects
  GetTransactions() {
    return this.httpClient.get(`${this.REST_API}/trans-list`);
  }
  GetMatchingTransactions() {
    return this.httpClient.get(`${this.REST_API}/trans-match`);
  }
  GetGeneratedMatchingFile() {
    return this.httpClient.get(`${this.REST_API}/trans-match-file`);
  }
  /**
   * GET /files-list
   * Purpose: Get all sheets ( files)
   */
  GetFileInfoList() {
    return this.httpClient.get(`${this.REST_API}/files-list`);
  }
  GetALLDataSources() {
    return this.httpClient.get(`${this.REST_API}/source`);
  }
  /**
   * GET /sources/:sourceId/sheets
   * Purpose: Get all sheets in a specific data source
   */
  GetALLFilesOfSource(sourceId: any) {
    return this.httpClient.get(`${this.REST_API}/sources/${sourceId}/sheets`);
  }
  /**
   * Delete /sources/:sourceId/sheets/:sheetId
   * Purpose: Delete specific file of a  data source
   */
  DeleteFileOfSource(sourceId: any, sheetId: any) {
    return this.httpClient.delete(
      `${this.REST_API}/sources/${sourceId}/sheets/${sheetId}`
    );
  }
  GetReportsHistory() {
    return this.httpClient.get(`${this.REST_API}/reports`);
  }
  // Error
  handleError(error: HttpErrorResponse) {
    let errorMessage = '';
    if (error.error instanceof ErrorEvent) {
      // Handle client error
      errorMessage = error.error.message;
    } else {
      // Handle server error
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    console.log(errorMessage);
    return throwError(errorMessage);
  }
}

I assume your modal component gets destoryed after closing it.我假设您的模态组件在关闭后会被破坏。 So the component properties are lost.因此组件属性丢失。 You could implement a service that is able to save your file infos temporarily and handle all of your requests.您可以实施一项能够临时保存文件信息并处理所有请求的服务。

For example:例如:

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

    fileInfoList: FileInfo[] = [];
    selectedFiles: FileInfo[] = [];

    constructor(private readonly _crudService: CrudService) { }

    loadDataSource(sourceId: string) {
        this._crudService.GetALLFilesOfSource(sourceId).subscribe((res) => {
            this.fileInfoList = res;
        });
    }

    check(id: string) {
        // checked file gets added to an array
        const file = this.fileInfoList.find(x => x._id === id);
        if (file != null) {
            this.selectedFiles.push(file);
        }
    }

    compare() {
        // call endpoint after save
        this._crudService.compareFiles(this.selectedFiles.map(x => x._id)).subscribe((res) => {
            console.log(res);
        })
    }

}

interface FileInfo {
    _id: string;
    fileName: string;
    createdAt: string;
    NumberRecords: string;
}

So each modal can inject this service and is able read the files that were selected from a previous modal.所以每个模态都可以注入这个服务,并且能够读取从前一个模态中选择的文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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