0

I've got a strange error...

I generate dynamic components in the template (a few).

Some of them has property form, which is the FormGroup created via FormBuilder, along with isValid() method.

isValid() returns boolean that depends on this.form.valid value.

The last dynamic component is always responsible for saving data. It has save() method that:

  • Loads all generated dynamic components
  • Checks if they have isValid() method
  • Then calls above method

It works pretty good! But sometimes... I get an error in the console, that says form is undefined.

What's the problem? Some async stuff?

Wrong hook in the dynamic components? I use ngOnInit() for assigning form property...

SOME CODE PARTS AS EXAMPLE

Dynamic component:

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

  constructor(private workflowService: WorkflowService) { }

  public form: FormGroup;
  public displayErrors = false;

  ngOnInit(): void {
    this.form = new FormGroup({});
  }

  public isValid(): boolean {
    const isValid: boolean = this.form.valid; // ERROR: can't get valid of undefined

    if (isValid) {
      this.displayErrors = false;
      return true;
    } else {
      this.displayErrors = true;
      return false;
    }
  }

}

Dynamic component that checks other component's valid status:

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

  constructor(private workflowService: WorkflowService) { }

  msg: string;

  ngOnInit(): void {}

  onSave() {
    this.msg = '';
    let components = this.workflowService.getComponents();
    let isError:boolean = false;

      components.forEach((comp: any) => {
        if(typeof comp['isValid'] === 'function') {
          if(!comp.isValid()) { /* HERE I GET ERROR SOMETIMES */
            this.msg = 'some text';
            isError = true;
          }
        }
      });
      
    }
      
  }

}
Jakub
  • 3
  • 5
  • It seems that `ngOnInit` is sometimes not called before `isValid`. It would be helpful if you could create Stackblitz with your code (relevant parts of code) so it would be possible to see how you use the components and how it is possible that sometimes they're intialized and sometimes not. Yet another possibility is that some code outside those two classes you showed assigns `undefined` to `form` attribute of `CCApplicationVerificationComponent` – Pawel Woroniecki Sep 25 '21 at 20:58
  • If you enabled [strict](https://angular.io/guide/strict-mode) mode in typescript, you wouldn't have this issue at runtime. You would be forced to check if `form` is present before doing `this.form.valid` – Prabh Sep 25 '21 at 21:39
  • Unfortunately your code examples are not enough to tell the problem. It is clear, that ngOnInit() is not getting called after the creation of the class in those cases. But: StackOverflow should not help you to solve the problems in your actual code, but to show you ideas or even specific solutions to help you fix your own code. So maybe you'd like to check out this page too: https://stackoverflow.com/questions/56427104/when-is-oninit-event-triggered-for-a-dynamically-loaded-angular-component. – Janos Vinceller Sep 25 '21 at 22:03
  • @JanosVinceller I'm not really sure if ngOnInit is not called at all... I temporary added button to call isValid() method and IT WORKED! Without refreshing the page I clicked the button in the last dynamic component and it returned above error :/ – Jakub Sep 25 '21 at 22:19
  • Look at my answer there: https://stackoverflow.com/a/66990451/12834967 – Costly Developer Sep 25 '21 at 22:32

1 Answers1

0

After hours of debugging I figured this out.

I had a memory leak, because I forgot to add Subscription to the SubArray, which is unsubscribed later in the ngOnDestroy() hook.

So due to repeatable .subscribe() app loaded component instances multiple times, then they were not displaying in the view, so ngOnInit() didn't triggered = didn't assign a value to the form property.

Jakub
  • 3
  • 5