Search code examples
javascriptangulartypescriptform-controlformgroups

Angular 9 - Form Group Issue


Disclaimer: I am new to angular and TS in general.

What I am trying to accomplish is an activation component that either submits a code directly to the service if it's in the URL param query. And if not have the user be able to insert the code into the form and submit it to the service that way.

The field is disabled when there's a code in the URL query and enabled when not, so that works fine. The issue I am bumping against has to do with the submission to the service.

I am getting the following error;

ERROR TypeError: Cannot read property 'get' of undefined
at ActivationComponent.handleActivation (activation.component.ts:48)

On that line 48, I had this.validateform.value in the past which resulted in the same error.

I've been messing with this for such a long time now, trying different approaches that I kind of lost my way...

Here's the component.ts:

import {Component, Input, Output, EventEmitter, AfterViewInit, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {AuthService} from '../auth/auth.service';

@Component({
  selector: 'app-activation',
  templateUrl: './activation.component.html',
  styleUrls: ['./activation.component.scss']
})
export class ActivationComponent implements OnInit {
  validateForm!: FormGroup;
  showModal = false;
  isConfirmLoading = false;
  activationCode: string;
  error: string;
  success: string;

  constructor(private router: Router,
              private fb: FormBuilder,
              private activatedRoute: ActivatedRoute,
              private authService: AuthService) {
    this.activatedRoute.queryParams.subscribe(params => {
      const code = params.code;
      if (code){
        this.isConfirmLoading = true;
        this.handleActivation(code);
      }
    });
  }

  ngOnInit() {
    this.showModal = true;
    this.validateForm = new FormGroup({
      CODE: new FormControl({value: this.activationCode, disabled: this.isConfirmLoading}, Validators.required)
    });
  }

  handleActivation(code){
    this.error = null;
    this.activationCode = code;
    if (code === null){
      if (!this.validateForm.valid) {
        console.log('Invalid Form');
        return;
      }
    }
    this.authService.activate(this.validateForm.get('CODE'))
      .subscribe(data => {
        console.log('SUCCESS!');
        console.log(data);
      },
        error => {
        console.log('ERROR!');
        console.log(error);
        });
  }

  onClose() {
    this.showModal = false;
    // Allow fade out animation to play before navigating back
    setTimeout(
      () => this.router.navigate(['..']),
      100
    );
  }

  onDialogClick(event: UIEvent) {
    // Capture click on dialog and prevent it from bubbling to the modal background.
    event.stopPropagation();
    event.cancelBubble = true;
  }
}

And this is the HTML currently:

<div id="backdrop" class="modal-backdrop fade" [ngClass]="{ show: showModal }"></div>
<div class="modal d-block fade"
     [ngClass]="{ show: showModal }"
     (click)="onClose()"
     id="listing-dialog"
     tabindex="-1" role="dialog" aria-labelledby="modalIdLabel">
  <nz-modal class="modal" [nzWidth]="600" [(nzVisible)]="showModal" nzTitle="NETCOT Account Activation" [nzFooter]="modalFooter">

    <nz-alert *ngIf="success" class="alert" nzType="success" nzMessage="{{success}}"></nz-alert>
    <nz-alert *ngIf="error" class="alert" nzType="error" nzMessage="{{error}}"></nz-alert>

  <form nz-form [formGroup]="validateForm" (ngSubmit)="handleActivation(null)">
    <nz-form-item>
      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="CODE">Activation Code</nz-form-label>
      <nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid activation code!">
        <!--<input *ngIf="isConfirmLoading" disabled nz-input [value]="activationCode" formControlName="CODE" id="CODE"/>-->
        <input  nz-input formControlName="CODE" id="CODE"/>
      </nz-form-control>
    </nz-form-item>
  </form>
  <ng-template #modalFooter>
    <button class="button" nz-button nzType="primary" (click)="handleActivation(null)" [nzLoading]="isConfirmLoading">Activate</button>
  </ng-template>
  </nz-modal>
</div>


Solution

  • here you code in constructor is executed before the ngOnInit() method gets executed, So there is no initialized form and you are trying to use that form.

    So just change the position of your subscription as shown below. This would surely resolve your issue.

         constructor(private router: Router,
                  private fb: FormBuilder,
                  private activatedRoute: ActivatedRoute,
                  private authService: AuthService) {
       
      }
    
      ngOnInit() {
        this.showModal = true;
        this.validateForm = new FormGroup({
          CODE: new FormControl({value: this.activationCode, disabled: this.isConfirmLoading}, Validators.required)
        });
     this.activatedRoute.queryParams.subscribe(params => {
          const code = params.code;
          if (code){
            this.isConfirmLoading = true;
            this.handleActivation(code);
          }
        });
      }