1

Disclaimer, this is my first Angular project. So bare with me.

What I want is multiple tables with inputs to change their number of rows based on a drop down menu: enter image description here

When the drop down circled in red is changed, the number of rows in each of the tables will change.

The drop down menu is in one component. Each table is its own component (app-input-tables) used four times. It is set up like this:

    <select class = "dropDown" #types (change)="onSelected(types.value)">
       options...
    </select>
    </div>
    <div><app-input-table></app-input-table></div>
    <div><app-input-table></app-input-table></div>
    <div><app-input-table></app-input-table></div>
    <div><app-input-table></app-input-table></div>

The "onSelected" method looks like this:

    inputs1: InputTableComponent = new InputTableComponent()
    inputs2: InputTableComponent = new InputTableComponent()
    inputs3: InputTableComponent = new InputTableComponent()
    inputs4: InputTableComponent = new InputTableComponent()

    onSelected(value:string): void {
    this.inputs1.typeEntry(value);
    this.inputs2.typeEntry(value);
    this.inputs3.typeEntry(value);
    this.inputs4.typeEntry(value);
    }

The app-input-table html looks like this:

<div>
  <label>SINT</label>
  <table>
    <tr *ngFor="let row of inputs; let i = index; trackBy:trackByFn">
      <td> <input class = "inputValues" [(ngModel)]="inputs[i]" (keyup.tab)="valueEntry()" /></td>
    </tr>
  </table>
</div>

My trackByFn and typeEntry methods look like this:

  trackByFn(index: any, item: any){
    return index;
  }

  typeEntry(selectedType: string) {
    if (selectedType == "BOOL")
      this.inputs = Array(8).fill(0);
    else
      this.inputs = Array(1).fill(0);

    this.changeDetection.detectChanges()
  }

So I want the *ngFor to update when the drop down menu changes.

So I tried to follow the instructions here:

I've been trying to follow the "ChangeDetectorRef" suggestion given in the answers. If I do the following:

constructor(
    private changeDetection: ChangeDetectorRef
  ) { }

I get the following compile time error: "An argument for 'changeDetection' was not provided."

If I move the changeDetection parameter from the constructor to a private field:

export class InputTableComponent implements OnInit {
  inputs: number[] = [];
  private changeDetection: ChangeDetectorRef

I do not get the compile time error. But I then get a runtime error when it it reads "this.changeDetection.detectChanges()" line:

  typeEntry(selectedType: string) {
    if (selectedType == "BOOL")
      this.inputs = Array(8).fill(0);
    else
      this.inputs = Array(1).fill(0);

    this.changeDetection.detectChanges()
  }

The error is: "Cannot read properties of undefined (reading 'detectChanges')"

I'm not sure what I'm doing wrong. I have imported the ChangeDetectorRef:

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';

I have also tried the ChangeDetectionStrategy.Default. Which was another answer on that page, but that didn't help either.

Any help would be great. Thanks.

  • Why do you instantiate the InputTableComponents and where do you eventually use the instantiated InputTableComponents ? To me it seems as if you don't use `inputs1`, `inputs2` etc. at all? Did you expect that `inputs1` would automatically map to the first `
    ` ?
    – kellermat Jan 07 '23 at 21:53
  • Btw: I would recommend you to create a stackblitz-example. This would make it much easier for other users to resolve your issues. – kellermat Jan 07 '23 at 22:01
  • I guess I did assume. The idea is the four tables are the four instances. I thought I needed to instantiate them to use four copies of the class. Do I not? – Anthony Meeks Jan 07 '23 at 22:14
  • Unfortunately your assumption is wrong. When you write `` the framework will automatically instantiate and render an InputTableComponent. Yet it is in no way associated to the Component you instantiated manually. Btw: In Angular you rarely instantiate Components manually. – kellermat Jan 07 '23 at 22:23
  • Maybe you could do some research on how Angular components usually communicate with each others. Or you could really provide a stackblitz-version of your code, so it would be possible to refactor it a bit. – kellermat Jan 07 '23 at 22:30
  • 1
    It was more of a "didn't think about " than it was an assumption. But thank you. I guess I had a huge blind spot on how components communicated with each other. I'll research and fix my code accordingly. If that doesn't fix the problem, I'll post it to stackblitz. Again thanks. – Anthony Meeks Jan 07 '23 at 22:48
  • 1
    Ok, I did the research you suggested. I guess I was instantiating the app-input-table class eight times, and I was using the four that were not connected to the html file. So I removed the manually instantiated classes. And add the @inputs decorator, linked the parent child properties, and everything worked with the ngOnChanged methode. Thanks for your help and clueing my into where I was going wrong. – Anthony Meeks Jan 08 '23 at 04:35
  • Perfect. Maybe you can post the working code as an answer to your own question? In this way other users could benefit as well ;-). – kellermat Jan 08 '23 at 09:03
  • Also note that from your usage, you shouldn't need to use change detection directly? So long as `this.inputs` is changed to a completely different object, Angular will detect the change. E.g. if you have a 4-item array and you change one of the values of it, no bueno. If you *copy* that 4-item array so that it's a 'new' array, Angular will detect it has changed and update as desired - e.g. `this.inputs = [...this.inputs];`. – Krenom Jan 08 '23 at 09:49

1 Answers1

0

It turns out my problem had nothing to do with how I was using change detection. My problem was with how I was trying to reference other components within a component. I instantiated a class (not a component) in my typescript file, not realizing the component itself wasn't instantiated.

So I followed the guidelines described here: https://angular.io/guide/inputs-outputs

And completely restructured my project to match these guidelines. After doing that, I was able to use the ngChange interface to detect my needed changes.