Search code examples
angular-materialangular11

Properties not getting value in ngOnIt() in Angular 11


I am getting the data from the database using an Api which is in the LeaveService. To get the data the method used is applyLeaveGet(id:string) which is in LeaveService. This method provides certain values like the joiningDate from the database. I am using Angular Material UI with reactive form.

The issue is that even though the leave instance is getting the data, but the in ngOnInt(), the properties are not getting the values.ngOnInt() does get triggred. For example I get the error undefined for joining date. How can I solve the issue. Thank you for the help

LeaveService : applyLeaveGet(id:string) method

applyLeaveGet(id:string){
    return this.http.get<Leave>('https://localhost:44330/api/leave/ApplyLeaveGet/'+ id);
  }

ApplyLeave Component

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup} from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { AuthenticationService } from 'src/app/authentication.service';
import { Leave } from '../interfaces/leave';
import { LeaveService } from '../services/leave.service';

@Component({
  selector: 'app-add-edit-leave',
  templateUrl: './add-edit-leave.component.html',
  styleUrls: ['./add-edit-leave.component.css']
})
export class AddEditLeaveComponent implements OnInit {

 form: FormGroup;
 currentDate = new Date();
  minDate: Date;
  maxDate: Date;

  selectedFile: File = null;
  url : any;


  leave :Leave;
  
  constructor(private fb: FormBuilder, private http: HttpClient
    ,private leaveService : LeaveService
    ,private route : ActivatedRoute
    ,private authenticationService: AuthenticationService
    ) {

     leaveService.applyLeaveGet(authenticationService.getUserId())
      .subscribe(data =>
        this.leave = data
       );

    // Set the minimum to January 1st 20 years in the past and December 31st a year in the future.
    const currentYear = new Date().getFullYear();
    this.minDate = new Date(currentYear - 20, 0, 1);
    this.maxDate = new Date(currentYear + 1, 11, 31);
     }
   
  ngOnInit() {
    this.form = this.fb.group({
      "currentDate": new FormControl(this.currentDate.toISOString().split("T")[0]),
      "joiningDate":[''],
      "fromDate":[''],
      "tillDate":[''],
      "leaveType":[''],
      "duration":[''],
      "reason":[''],
      "filePath":['']
  });
  
  }


  onSelectFile(event: any) {
    this.selectedFile = <File>event.target.files[0];
    if (event.target.files && event.target.files[0]) {
            var reader = new FileReader();
            reader.onload = (event: any) => {
                this.url = event.target.result;
            }
            reader.readAsDataURL(event.target.files[0]);
        }
        else
        {
          this.url = "";
        }
  
  }
  
  onSubmit(){
    var userId = this.authenticationService.getUserId();
    const formData = new FormData();
    formData.append('userId', userId);
    formData.append('currentDate', this.form.value.fullName);
    formData.append('joiningDate', this.form.value.fullName);
    formData.append('fromDate', this.form.value.fullName);
    formData.append('tillDate', this.form.value.fullName);
    formData.append('leaveType', this.form.value.fullName);
    formData.append('duration', this.form.value.fullName);
    formData.append('reason', this.form.value.fullName);
    formData.append('balanceAnnualLeave', this.form.value.fullName);
    formData.append('balanceSickLeave', this.form.value.fullName);
    formData.append('balanceAnnualLeave', this.form.value.fullName);
    formData.append('File', this.selectedFile);
  }
}

this is the html

<p>add-edit-leave works!</p>
<div class="container">
    <form class="form-container" [formGroup]="form" (ngSubmit)="onSubmit()">
        <mat-card>
            <mat-card-header>
                <mat-card-title>Apply Leave</mat-card-title>
            </mat-card-header>
            <mat-card-content>
                <div class="row">
                    <div class="col-md-6">
                        <mat-form-field class="full-width">
                            <mat-label>Today's Date</mat-label>
                            <input formControlName="currentDate" type="date" class="form-control" matInput placeholder="Today's Date" readonly > 
                        </mat-form-field>
                    </div>
                    
                    <div class="col-md-6">
                        <mat-form-field class="full-width">
                            <mat-label>Joining Date</mat-label>
                            <input formControlName="joiningDate" type="datetime" class="form-control" matInput  placeholder="Joining Date">
                        </mat-form-field>
                    </div>
                </div>
                <!--Date Requested For-->
                <div class="row">
                    <div class="col-md-6">
                        <mat-form-field class="full-width" appearance="fill">
                            <mat-label>From Date</mat-label>
                            <input matInput formControlName="fromDate" [min]="minDate" [max]="maxDate"
                                [matDatepicker]="picker">
                            <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
                            <mat-datepicker #picker></mat-datepicker>
                        </mat-form-field>
                    </div>
                    <div class="col-md-6">
                        <mat-form-field class="full-width" appearance="fill">
                            <mat-label>Till Date</mat-label>
                            <input matInput formControlName="tillDate" [min]="minDate" [max]="maxDate"
                                [matDatepicker]="pickerTillDate">
                            <mat-datepicker-toggle matSuffix [for]="pickerTillDate"></mat-datepicker-toggle>
                            <mat-datepicker #pickerTillDate></mat-datepicker>
                        </mat-form-field>
                    </div>

                </div>
                <!--Leave Type Duration(dropdown box)-->
                <div class="row">
                    <div class="col-md-6">
                        <mat-form-field class="full-width" appearance="fill">
                            <mat-label>Leave Type</mat-label>
                            <select formControlName="leaveType" matNativeControl id="mySelectId">
                                <option value="" disabled selected></option>
                                <option value="Annual Leave">Annual Leave</option>
                                <option value="Sick Leave">Sick Leave</option>
                            </select>
                        </mat-form-field>
                    </div>
                    <div class="col-md-6">
                        <mat-form-field class="full-width" appearance="fill">
                            <mat-label>Duration</mat-label>
                            <select formControlName="duration" matNativeControl id="mySelectId">
                                <option value="" disabled selected></option>
                                <option value="Full Day ">Full Day</option>
                                <option value="First Half Day">First Half Day</option>
                                <option value="Second Half Day">Second Half Day</option>
                            </select>
                        </mat-form-field>
                    </div>
                </div>
                <!--Reason-->
                <div class="row">
                    <div class="col-md-12">
                        <mat-form-field class="full-width">
                            <mat-label>Reason</mat-label>
                            <input formControlName="reason" matInput placeholder="Reason">
                        </mat-form-field>
                    </div>
                </div>
 
                <div class="row">
                    <div class="col-md-6">
                        <mat-label>Leave Balacne</mat-label><br>
                        <ul>
                            <li>
                                annualLeaveBalacne: <span>{{leave.balanceAnnualLeave}}</span> <br>
                            </li>
                            <li>
                                sickLeaveBalance: <span>{{leave.balanceSickLeave}}</span>
                            </li>
                        </ul>
                    </div>
                </div>
                <!--Submit-->
                <mat-card-actions>
                    <button mat-stroked-button type="submit>Basic</button>
                </mat-card-actions>
            </mat-card-content>
        </mat-card>

    </form>
</div>

Solution

  • In the current version of your question it does not look like you are any setting values from this.leave in the form in OnInit. From your problem description and the rest of your code I think your problem is the asynchronous call of LeaveService in the constructor. As it it asynchronous code it might not be finished before ngOnInit is called and executed, thus the error messages about undefined values. You have to wait untill the HTTP call is finished before accessing the data.

    As you should not perform potentially long running HTTP calls in the constructor, I suggest moving that part in OnInit. Everything that's not long running and asynchronous can be performed in the constructor. Your code could be refactored like this:

    constructor(private fb: FormBuilder,
      private http: HttpClient,
      private leaveService : LeaveService,
      private route : ActivatedRoute,
      private authenticationService: AuthenticationService
    ) {
        // Set the minimum to January 1st 20 years in the past and December 31st a year in the future.
        const currentYear = new Date().getFullYear();
        this.minDate = new Date(currentYear - 20, 0, 1);
        this.maxDate = new Date(currentYear + 1, 11, 31);
    
        this.form = this.fb.group({
            "currentDate": new FormControl(this.currentDate.toISOString().split("T")[0]),
            "joiningDate": [''],
            "fromDate": [''],
            "tillDate": [''],
            "leaveType": [''],
            "duration": [''],
            "reason": [''],
            "filePath": ['']
        });
    }
    
    ngOnInit() {
        leaveService.applyLeaveGet(authenticationService.getUserId())
          .subscribe(data =>
            {
                this.leave = data;
    
                // now data is here and can be used to set initial form values, example:
                this.form.get('leaveType').setValue(this.leave.Type);
            }
        );
    }