title: Update parent when variable in child change - Angular
body: <p>I have a parent which is a form.
  This form is composed of two child components:</p>
  
  <p><strong>experiment create (parent)</strong></p>
  
  <ul>
  <li>creation-dataset (child)</li>
  <li>creation-metadata (child)</li>
  </ul>
  
  <p>I use a angular component -> mat-accordion to navigate through the two children components.
  I use @Input to have the result of what is filled in the children component into the parent.
  I want to submit the form only if a file is chosen for both of them. Therefore, I set a variable (<strong>in datasetList[i].fileValid</strong>) to say whether a file has been selected. Like this I disabled the button if a file is not updated. To disable the button I called the two function:</p>
  
  <ul>
  <li>isDatasetFilesValid()</li>
  <li>isMetadataFilesValid()</li>
  </ul>
  
  <p>However, when the variable changed for the second child component it does not updated the disabled button.
  This works, only if I press "previous" and "next". The button is not disabled anymore. Like if I needed to reload or refresh the parent. Maybe because of the life cycle ?</p>
  
  <p><strong>Parent Component:</strong></p>
  
  <pre><code>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;
      });
    }
  }
  </code></pre>
  
  <p><strong>Parent HTML:</strong></p>
  
  <pre><code>&lt;div class="jumbotron"&gt;
    &lt;div class="container"&gt;
      &lt;div class="row"&gt;
        &lt;div class="col-sm-8 offset-sm-2"&gt;
  
          &lt;form name="form" (ngSubmit)="f.form.valid" #f="ngForm" novalidate&gt;
  
            &lt;mat-accordion class="headers-align"&gt;
  
              &lt;mat-expansion-panel id="datasetUpload" [expanded]="step === 0" (opened)="setStep(1)" hideToggle="true"&gt;
  
                &lt;app-creation-dataset [datasetList]="datasetList"&gt;&lt;/app-creation-dataset&gt;
  
                &lt;mat-action-row&gt;
                  &lt;button mat-button color="warn" (click)="prevStep()"&gt;Previous&lt;/button&gt;
                  &lt;button mat-button color="primary" (click)="nextStep()"&gt;Next&lt;/button&gt;
                &lt;/mat-action-row&gt;
              &lt;/mat-expansion-panel&gt;
  
              &lt;mat-expansion-panel id="metadataUpload" [expanded]="step === 1" (opened)="setStep(2)" hideToggle="true"&gt;
  
                &lt;app-creation-metadata [metadataList]="metadataList"&gt;&lt;/app-creation-metadata&gt;
  
                &lt;mat-action-row&gt;
                  &lt;button mat-button color="warn" (click)="prevStep()"&gt;Previous&lt;/button&gt;
                  &lt;button mat-button color="primary" type="submit" [disabled]="(isMetadataFilesValid() != -1) &amp;&amp; (isDatasetFilesValid() != -1)" (click)="createExperiment()"&gt;End&lt;/button&gt;
                &lt;/mat-action-row&gt;
              &lt;/mat-expansion-panel&gt;
  
            &lt;/mat-accordion&gt;
  
          &lt;/form&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>Child Component:</strong></p>
  
  <pre><code>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) =&gt; {
          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) =&gt; {
          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);
    }
  }
  </code></pre>
  
  <p><strong>Child HTML:</strong></p>
  
  <pre><code>&lt;div *ngFor="let dataset of datasetList; let index = index"&gt;
    &lt;div id="datasetFiles"&gt;
      &lt;h6&gt;Select the type of dataset and browse the files:&lt;/h6&gt;
      &lt;div class="container"&gt;
        &lt;div class="row justify-content-between"&gt;
          &lt;div class="col-6 d-flex align-items-center"&gt;
            &lt;input id="file" #file (change)="onChange(file.files, index, $event.currentTarget)" type="file"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;button mat-icon-button color="primary" (click)="addDataset()"&gt;
      &lt;mat-icon&gt;add_box&lt;/mat-icon&gt;
    &lt;/button&gt;
  &lt;/div&gt;
  </code></pre>