Search code examples
angulartypescriptobservableangular-reactive-forms

Variable not working properly with Reactive Form & Async Service Calls in Angular


Page Design:

  • I have a UI Page which is used to Create/Edit User Role Details in my Angular Application.
  • The page takes a "role_key" as input from URL route params. I subscribe to that route params and get that role_key.
  • If role_key exists in route params then i make another api call to get details about to that role. The same data is then bind to the reactive form. Else an empty form is rendered.
  • Based on the role_key, i display either create/update & delete buttons below the form.
  • Create button is displayed when there is no role_key in url params. Update & Delete buttons are displayed when there is a role_key in url params.

Issue:

The issue is that, even when a role_key exist in route params & a successful api call is made to get the role details about the role_key, the reactive form is still empty and the action buttons, edit & delete are not displayed. Similary if role_key doesn't exist in the route params, an empty form is rendered but the Create button is not rendered.

Here is my codeblock:

edit-role.component.html

<div class="row">
<div class="col-lg-12 col-md-12">
  <div class="card">
    <div class="">
      <div class="row">
        <div class="col-md-12 col-lg-12 col-xl-12 d-block">
          <div class="card border-0 card-body shadow-none">
            <!-- <h5>Roles Detail</h5> -->
            <form [formGroup]="roleForm" class="form-horizontal" id="roleForm" name="roleForm"
              data-toggle="validator" role="form">
              <div class="row">
                <div class="col-md-6">
                  <div class="form-group">
                    <label for="group_name" class="field-label">Key<span style="color: red"> *</span></label>
                    <input type="text" class="form-control text-field" id="role_key" name="role_key"
                      formControlName="role_key" placeholder="Enter role key" [readonly]="role_key" />
                  </div>
                </div>

                <div class="col-md-6">
                  <div class="form-group">
                    <label for="group_id" class="field-label">Name<span style="color: red"> *</span></label>
                    <input type="text" class="form-control text-field" id="role_name" name="role_name"
                      formControlName="role_name" placeholder="Enter role name" />
                  </div>
                </div>
              </div>
              <div class="row">
                <div class="col-md-6">
                  <div class="form-group">
                    <label for="group_description" class="field-label">Description<span style="color: red">
                        *</span></label>
                    <textarea class="form-control text-field" id="role_description" name="role_description"
                      formControlName="role_description" placeholder="Enter role description">
                    </textarea>
                  </div>
                </div>
              </div>

              <div class="row mg-t-40" style="width: 100% !important;">
                <div class="col-md-12 text-left" style="text-align: center !important;">
                  <button type="button" class="btn btn_update mr-3" (click)="goToList()">
                    Back
                  </button>
                  <button type="button" class="btn btn_update mr-3" *ngIf="role_key == ''"
                    [disabled]="!roleForm.valid" (click)="
                      submitRoleDetails(roleForm.value, roleForm.valid)
                    ">
                    Create
                  </button>
                  <button type="button" class="btn btn_update mr-3" *ngIf="role_key != ''"
                    [disabled]="!roleForm.valid" (click)="
                      submitRoleDetails(roleForm.value, roleForm.valid)
                    ">
                    Update
                  </button>
                  <button type="button" class="btn btn_update mr-3" *ngIf="role_key != ''"
                    (click)="deleteRole(role_key)">
                    Delete
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

TS File - edit-role.component.ts

// variables
  roleForm: FormGroup;
  loader: boolean = false;
  roleDetails: any;
  role_key: string = '';

  edit: boolean = false


  constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private router: Router, private toaster: ToasterService, private userService: UsersService) {

  }

  ngOnInit(): void {
    try {
      this.createNewRoleForm();
      this.route.queryParams.subscribe(res => {
        if (res && res.role_key) {
          this.role_key = res.role_key
          this.getRoleDetails();
          this.edit = true;
        }
        else {
          this.role_key = '';
          this.edit = false;
        }
      });
    }
    catch (Ex) {

    }
    finally {
    }

  }

  // create new role form
  createNewRoleForm() {
    this.roleForm = this.formBuilder.group({
      role_key: new FormControl('', Validators.required),
      role_name: new FormControl('', Validators.required),
      role_description: new FormControl('', Validators.required)
    });
    this.edit = false;
  }

  // get role details
  getRoleDetails() {
    try {
      this.loader = true;
      this.userService.getRoleDetails(this.role_key).subscribe((data) => {
        if (data && data.data) {
          this.roleDetails = data.data;
          this.roleForm.controls.role_key.setValue(this.roleDetails.role_key);
          this.roleForm.controls.role_name.setValue(this.roleDetails.role_name);
          this.roleForm.controls.role_description.setValue(this.roleDetails.role_description);
        }
      }, (error) => {
        this.loader = false;
        this.toaster.error('No Role Found', 'Error');
      });
    }
    catch (ex) { }
    finally {
      this.loader = false;
    }
  }

  
  // delete role
  deleteRole(role_key: string) {
    //delete
  }

  // create / edit role details
  submitRoleDetails(value: any, valid: boolean) {
    if (valid) {
      let payload: any = {};
      payload = JSON.parse(JSON.stringify(value));
      if (this.role_key) {
        this.updateRole(payload);
      } else {
        this.createRole(payload);
      }
    }
  }

  // create role
  createRole(payload) {
     //create
  }

  // update role
  updateRole(payload) {
    //update
  }

The edit page is invoked as follows: usermanagement/edit-role?role_key=consultant

Sad Part is this issue is not occuring when i run this code locally, but once it is deployed to a dev or test environment, this issue occurs. So, it is hard for me to reproduce it locally. I have attached the screenshot of the same.

Page that works properly in local

Page working properly in local

Page that has issue after deployed to test/dev

Page not working after deployed to test/dev

So, please help me let me know where and why this code breaks? Is it due to any wrong Async handling or any other issue let me know.


Solution

  • I have fixed the issue. The issue occurred due to a confusion in the app-routing.module.ts code.

    1. In lazy loading, for the 'usermanagement/' route i have configured the module 'user-mgmt' as children inside loadChildren ().
    2. But in the route-component mapping inside Routes [], i have used mentioned the 'edit-role' component inside the 'users' module (which is unused).
    3. Both the user-mgmt and users modules had this same 'edit-role' component with the same code.

    This seems to have caused the confusion when the code was deployed and run in the test environment.