Add FormControl accroding to the data returned from backend but got two different error in Angular app

做~自己de王妃 提交于 2020-03-04 19:00:20

问题


This is one of the page of my Angular app.

Inside the ngOnInit method, I call the api twice to get different data I need and loop through the data by using forEach method to build reactive form, but somehow, I encountered one of two different error.

This

enter image description here

and this

enter image description here

and sometime there is no error at all.

It would be grateful if someone can tell me what's wrong with my code.

here is part of my code

user-manager.component.ts

export class UserManagerComponent implements OnInit {
    constructor(
    private fb: FormBuilder
  ) {}
    ngOnInit(): void {
        this.commonData.getDropdownData('menus')
        .pipe(takeWhile(() => this.alive))
        .subscribe(r => {
          if (r.status === 0) {
            this.menuForm = this.fb.group({});
            this.menuList = r.result.menus;
            this.menuList.forEach(i => {
              const control = new FormControl();
             (this.menuForm as FormGroup).setControl(i.MenuId, control);
              i.children.forEach(a => {
                const con = new FormControl();
                (this.menuForm as FormGroup).setControl(a.MenuId, con);
              });
            });
            this.isMenuFormReady = true;
      } else {
        this.toastrService.danger(r.message);
      }
    },
      error => {
        if (!environment.production) {
          this.menuForm = this.fb.group({});
          this.menuList = menuMock.menus;
          this.menuList.forEach(i => {

            const control = new FormControl();

            (this.menuForm as FormGroup).setControl(i.MenuId, control);

            i.children.forEach(a => {
              const con = new FormControl();
              (this.menuForm as FormGroup).setControl(a.MenuId, con);
            });

          });
          this.isMenuFormReady = true;
        }
          console.log(error);
      });

    this.commonData.getDropdownData('permissions')
    .pipe(takeWhile(() => this.alive))
    .subscribe(r => {
      if (r.status === 0) {
        this.permissionsForm = this.fb.group({});
        this.permissionsList = r.result;
        this.permissionsList = this.groupBy(this.permissionsList, function(item) {
          return [item.GroupId];
      });

      this.permissionsList.forEach(i => {

        const id = i[0].GroupId;
        this.permissionsForm.addControl(id, this.fb.group({}));

        i.forEach(a => {
          const con = new FormControl();
          (this.permissionsForm.get(id) as FormGroup).addControl(a.ActionId, con);
        });
      });
      this.isPermissionFormReady = true;

      } else {
        this.toastrService.danger(r.message);
      }
    },
      error => {
        if (!environment.production) {
          this.permissionsForm = this.fb.group({});
          this.permissionsList = userMock.Permission;
          this.permissionsList = this.groupBy(this.permissionsList, function(item) {
            return [item.GroupId];
        });

          this.permissionsList.forEach(i => {

            const id = i[0].GroupId;
            // console.log('id: ', id)
            this.permissionsForm.addControl(id, this.fb.group({}));

            i.forEach(a => {
              const con = new FormControl();
              (this.permissionsForm.get(id) as FormGroup).addControl(a.ActionId, con);
            });
          });
          this.isPermissionFormReady = true;
          // console.log(this.permissionsForm);
        }
          console.log(error);
      });
  }
    groupBy( array , f ) {
        const groups = {};
        array.forEach( function(o) {
            const group = JSON.stringify( f(o) );
            groups[group] = groups[group] || [];
            groups[group].push( o );
        });
        return Object.keys(groups).map( function( group ) {
            return groups[group];
        });
    }
}

user-manager.component.html

      <nb-card>

          <nb-card-header>
            form1
          </nb-card-header>
          <nb-card-body>
              <form [formGroup]="permissionsForm" autocomplete="off" *ngIf="isPermissionFormReady">
            <nb-card *ngFor="let item of permissionsList; let i = index;" [formGroupName]="i">
              <nb-card-header>
                {{item[0].GroupName}}
              </nb-card-header>
              <nb-card-body class="pt-0">
                <div class="row">
                  <div class="col-4 my-1" *ngFor="let permission of item">
                    <label>
                      <input type="checkbox" [formControlName]="permission.ActionId"/>
                      {{permission.ActionName}}
                    </label>
                  </div>
                </div>
              </nb-card-body>
            </nb-card>
          </form>
          </nb-card-body>

        </nb-card>

        <nb-card>
            <nb-card-header>
              form2
            </nb-card-header>
            <nb-card-body>
              <form [formGroup]="menuForm" autocomplete="off" *ngIf="isMenuFormReady">
                <div class="row">
                    <div class="col-4" *ngFor="let menu of menuList" >
                        <nb-card>
                          <nb-card-header>
                            <label>
                              <input type="checkbox" id="{{menu.MenuId}}" [formControlName]="menu.MenuId" (change)="menuClick($event)"/>
                              {{menu.title}}
                            </label>
                          </nb-card-header>
                          <nb-card-body class="pt-0">
                            <div class="row">
                              <div class="col-12 my-1" *ngFor="let item of menu.children">
                                <label>
                                  <input type="checkbox" id="{{item.MenuId}}" [formControlName]="item.MenuId" (change)="menuClick($event)"/>
                                  {{item.title}}
                                </label>
                              </div>
                            </div>
                          </nb-card-body>
                        </nb-card>
                      </div>
                </div>
              </form>
            </nb-card-body>
          </nb-card>

回答1:


There is currently a bug in Chrome 80 which makes Array.reduce not to work according to the spec. So If you are using reactive form in your project you will face browser specific issue like ( form.get('key').value is undefined or valuechanges is undefined even if it exists), which was working fine in chrome 79. To fix this issue, add Array.reduce polyfill in your angular project manually as shown below.

Add this to main.ts

(function () {
 function getChromeVersion() {
 const raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);

 return raw ? parseInt(raw[2], 10) : false;
    }

 const chromeVersion = getChromeVersion();
 if (chromeVersion && chromeVersion >= 80) {
      Array.prototype.reduce = function (callback /*, initialValue*/) {
 'use strict';
 if (this == null) {
 throw new TypeError('Array.prototype.reduce called on null or undefined');
        }
 if (typeof callback !== 'function') {
 throw new TypeError(callback + ' is not a function');
        }
 let t = Object(this), len = t.length >>> 0, k = 0, value;
 if (arguments.length === 2) {
          value = arguments[1];
        } else {
 while (k < len && !(k in t)) {
            k++;
          }
 if (k >= len) {
 throw new TypeError('Reduce of empty array with no initial value');
          }
          value = t[k++];
        }
 for (; k < len; k++) {
 if (k in t) {
            value = callback(value, t[k], k, t);
          }
        }
 return value;
      };
    }
  })();

ForMoreInfo



来源:https://stackoverflow.com/questions/60221545/add-formcontrol-accroding-to-the-data-returned-from-backend-but-got-two-differen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!