【问题标题】:Update parent when variable in child change - Angular当子变量中的变量更改时更新父节点 - Angular
【发布时间】:2023-03-05 20:15:01
【问题描述】:

我有一个父母,它是一种形式。 此表单由两个子组件组成:

实验创建(父)

  • 创建数据集(子)
  • 创建元数据(子)

我使用 angular 组件 -> mat-accordion 来浏览两个子组件。 我使用@Input 将子组件中填充的结果填充到父组件中。 我只想在为他们俩都选择了文件的情况下提交表格。因此,我设置了一个变量(in datasetList[i].fileValid)来表示是否选择了文件。像这样,如果文件未更新,我禁用了该按钮。要禁用按钮,我调用了两个函数:

  • isDatasetFilesValid()
  • isMetadataFilesValid()

但是,当第二个子组件的变量发生更改时,它不会更新禁用的按钮。 只有当我按“上一个”和“下一个”时,这才有效。该按钮不再被禁用。就像我需要重新加载或刷新父级一样。也许是因为生命周期?

父组件:

export class ExperimentCreateComponent implements OnInit {
  data: any = {};
  datasetList: any = [{ fileValid: false }];
  metadataList: any = [{ fileValid: false }];

  // Functions to navigate through the expansion panels
  setStep(index: number) {
    this.step = index;
  }

  nextStep() {
    this.step++;
  }

  prevStep() {
    this.step--;
  }

  isDatasetFilesValid() {
    return this.datasetList.findIndex(function(item, i) {
      return item.fileValid == false;
    });
  }

  isMetadataFilesValid() {
    return this.metadataList.findIndex(function(item, i) {
      return item.fileValid == false;
    });
  }
}

父 HTML:

<div class="jumbotron">
  <div class="container">
    <div class="row">
      <div class="col-sm-8 offset-sm-2">

        <form name="form" (ngSubmit)="f.form.valid" #f="ngForm" novalidate>

          <mat-accordion class="headers-align">

            <mat-expansion-panel id="datasetUpload" [expanded]="step === 0" (opened)="setStep(1)" hideToggle="true">

              <app-creation-dataset [datasetList]="datasetList"></app-creation-dataset>

              <mat-action-row>
                <button mat-button color="warn" (click)="prevStep()">Previous</button>
                <button mat-button color="primary" (click)="nextStep()">Next</button>
              </mat-action-row>
            </mat-expansion-panel>

            <mat-expansion-panel id="metadataUpload" [expanded]="step === 1" (opened)="setStep(2)" hideToggle="true">

              <app-creation-metadata [metadataList]="metadataList"></app-creation-metadata>

              <mat-action-row>
                <button mat-button color="warn" (click)="prevStep()">Previous</button>
                <button mat-button color="primary" type="submit" [disabled]="(isMetadataFilesValid() != -1) && (isDatasetFilesValid() != -1)" (click)="createExperiment()">End</button>
              </mat-action-row>
            </mat-expansion-panel>

          </mat-accordion>

        </form>
      </div>
    </div>
  </div>
</div>

子组件:

export class CreationDatasetComponent implements OnInit {
  @Input() datasetList: any = [{ fileValid: false }];
  fileSelected: File;


  constructor(private papa: Papa, private cd: ChangeDetectorRef) {}

  ngOnInit() {}

  onChange(files: FileList, index: number, dom: any) {
    // Option to parse the file with papaparse
    let options = {
      header: true,
      error: (err, file) => {
        this.datasetList[index].fileValid = false;
        alert(
          "Unable to parse CSV file, please verify the file can be accessed and try again. Error reason was: " +
            err.code
        );
        return;
      },
      complete: (results, file) => {
        console.log("Parsed:", results, file);
        let filename = file.name;

        // Add the dataset to the datasetList
        this.datasetList[index].headers = results.meta.fields;
        this.datasetList[index].values = results.data;
        this.datasetList[index].filename = filename;
        this.datasetList[index].is_metadata = false;
        this.datasetList[index].fileValid = true;
        this.cd.detectChanges();
      }
    };
    this.fileSelected = files[0]; // Get the file
    // Call the function to parse the file, option is the callback
    this.papa.parse(this.fileSelected, options);
  }

  // Add a dataset form
  addDataset() {
    this.datasetList.push({ fileValid: false });
  }

  // Remove a dataset form
  removeDataset(index: number) {
    this.datasetList.splice(index, 1);
  }
}

子 HTML:

<div *ngFor="let dataset of datasetList; let index = index">
  <div id="datasetFiles">
    <h6>Select the type of dataset and browse the files:</h6>
    <div class="container">
      <div class="row justify-content-between">
        <div class="col-6 d-flex align-items-center">
          <input id="file" #file (change)="onChange(file.files, index, $event.currentTarget)" type="file">
        </div>
      </div>
    </div>
  </div>
</div>
<div>
  <button mat-icon-button color="primary" (click)="addDataset()">
    <mat-icon>add_box</mat-icon>
  </button>
</div>

【问题讨论】:

  • @Input 用于pass variables FROM parent TO child,而不是@Output 用于pass variables FROM child TO parent.. 参见:angular.io/guide/…
  • 所以我应该使用@output 而不是@input?然而,它有效,我的意思是当我将它发送到我的服务器时,我拥有父级中子级的值。
  • 您可以使用@Output 创建一个EventListener,它将您想要的变量传递给您的父组件。但是如果你想从父级初始化你的 children 变量,你仍然需要 Input
  • 我真的不需要在父级中初始化它。我可以在孩子中初始化它吗?
  • 是的,但您会失去“父值”。因此,如果您只想“要求您的父母更新一个值”,请创建一个输出事件,父母将听取然后更改您需要的内容。我可以举个例子

标签: javascript angular typescript


【解决方案1】:

所以,为了让这个答案更清楚,请阅读 cmets on question。

我将跳过@Output 的示例:

这是 CHILD.COMPONENT.TS

@Component({
  selector: 'children',
  templateUrl: './children.component.html',
  styleUrls: ['./children.component.scss'],
  providers: [{...
  })
})

export class ChildrenComponent {

  @Output() editedEmitter = new EventEmitter<number>();
  
  private variableToPass = 10;
  
  constructor() {}
  
  functionToCall() {
    this.editedEmitter.emit(20);
  }

这是 PARENT.COMPONENT.HTML

<section>
      <children (editedEmitter)="updateValue($event)"></children>
</section>

<!-- in the component you'll do 
  updateValue(val: number) {
    this.variableToUpdate = val;
  }
-->

【讨论】:

  • 其实我的问题不在这里。我的问题是我在回调中更改了“this.datasetList[index].fileValid = true”的值。因为如果我在回调之外更改值,它会起作用。
【解决方案2】:

[disabled] 需要一个条件(真或假),您输入的代码:isMetadataFilesValid() != -1 isDatasetFilesValid() != -1 不是一个合适的条件,它们是两个。如果您希望这两个条件都为真,请使用 &amp;&amp; 表示法。

[disabled]="(isMetadataFilesValid() != -1) && (isDatasetFilesValid() != -1)"

另外,我建议将条件移至函数本身,以便它们返回布尔值。

【讨论】:

  • 抱歉,是我把代码放到stackOverflow上的时候弄错了。我有这个。事实上,它对我所做的有效。只有当我选择一个文件时它才不会更新按钮,所以它仍然被禁用。但是,如果我按“上一个”和“下一个”,则该按钮不再被禁用。就像父母更新值一样。我认为它来自生命周期或类似的东西,但我不知道如何解决它
  • 查看其他 cmets。除此之外,我想说(ngSubmit) 需要一个函数而不是一个条件。 (ngSubmit) 在您的提交按钮被按下时被调用。因此,您无需在提交按钮上添加(click),而是将函数移至(ngSubmit)
猜你喜欢
  • 2018-11-25
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-08
  • 1970-01-01
  • 2015-05-03
相关资源
最近更新 更多