【问题标题】:I can't dynamically populate form with values on reload我无法在重新加载时使用值动态填充表单
【发布时间】:2021-06-14 23:16:20
【问题描述】:

这段代码工作正常,模板部分没问题,这里的问题是模板被这个静态值(角色、权限和管理器)填充得很好

但一旦我调用 API 并获取新值并更改角色对象或权限或管理器,表单就会读取初始空值

也许它与订阅有关?主题 ?我不确定,因为我是 Angular 的新手

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl, Validators  } from "@angular/forms";
import { ManagersService } from "../../managers/managers.service";
import { NotificationService } from "../../notification/notification.service";
import { PermissionsService } from "../../permissions/permissions.service";
import { HttpClient } from "@angular/common/http";
import { environment } from "../../../../environments/environment";
import { Router, ActivatedRoute } from "@angular/router";
import { RolesService } from "../roles.service";

@Component({
  selector: 'app-edit-role',
  templateUrl: './edit-role.component.html',
  styleUrls: ['./edit-role.component.css']
})
export class EditRoleComponent implements OnInit {
  isLoading: boolean = false;
  roleId: number = +this.route.snapshot.params['id']
  roles: any;
  originalRole: any = {};
  role = { name: '', permissions: [], managers: [] };
  // permissions: any = {};
  // roles: any = {};
  
  permissions = [
    { id: 1, name: 'Can create category' },
    { id: 2, name: 'Can read category' },
    { id: 3, name: 'Can update category' },
    { id: 4, name: 'Can destroy category' }
  ];
  managers = [
    { id: 1, name: 'Amir' },
    { id: 2, name: 'Asmaa' },
  ];    
  
    
  constructor(
    private http: HttpClient,
    private router: Router,
    private route: ActivatedRoute,
    private fb: FormBuilder,   
    private notificationService: NotificationService,
    private rolesService: RolesService,
    private managersService: ManagersService,
    private permissionsService: PermissionsService
  ) { 
  } 
  ngOnInit(): void {
    this.rolesService.getRoles().subscribe(response => {
this.roles = response.body;
    this.originalRole = this.roles.find((el: any) =>  el.id === this.roleId)
    // this.permissions = this.originalRole.permissions;

    this.form.patchValue({
      'role': {
        'name': this.originalRole.name,
        'permissions': this.originalRole.permissions.map(a => a.id),
        'managers': this.originalRole.managers.map(a => a.id)
      }
    });

    console.log(this.role);
    this.isLoading = false;
    },
    error => {
      this.isLoading = false;
      this.notificationService.showNotification(
        error.error.title,
        error.error.details,
        'error'
      );
    })
  }

  form = new FormGroup({
    role: new FormGroup({
      name: new FormControl(this.role.name, [Validators.required]),
      permissions: new FormArray(
        this.permissions.map(
          x => new FormControl(this.role.permissions.find(p => p == x.id) != null)
        )
      ),
      managers: new FormArray(
        this.managers.map(
          x => new FormControl(this.role.managers.find(p => p == x.id) != null)
        )
      )
    })
  });
  get name() {
    return this.form.get('role.name') as FormArray;
  }
get rolePermisions() {
    return this.form.get('role.permissions') as FormArray;
  }
  get roleManagers() {
    return this.form.get('role.managers') as FormArray;
  }
  submit(form: FormGroup) {
    if (form.valid) {
      const data = {
        role: {
          name: this.form.value.role.name,
          permisions: this.permissions
            .filter((x, index) => form.value.role.permissions[index])
            .map(x => x.id),
          managers: this.managers
            .filter((x, index) => form.value.role.managers[index])
            .map(x => x.id)
        }
      };
      console.log(data);
    }
  }
}

如上所示,使用静态权限数组是可以的,但是当我将新获取的数组分配给权限变量(注释掉的行)时,我仍然得到空的,我是否在这里遗漏了一些东西 -正确填充值?

更新

我不确定你们是否理解我 以更简单的方式

myRole: any = [];

  
  ngOnInit(): void {           
    this.rolesService.getRoles().subscribe(response => {
  
      let roles = response.body;
      let role = roles.find((el: any) =>  el.id === this.roleId)
      console.log(role)
      // This logs the role fine
      
      // Now setting the above variable
      this.myRole = role
    })

    console.log(this.myRole)
    // This NEVER want to be set, i know i'm missing something simple but i can't get it
  }

【问题讨论】:

  • 能否请您在stackbliz中模拟这个问题以便调试?
  • 您正在使用布尔默认值初始化permissionsmanagers 的表单控件,但随后在patchValue 调用中将它们设置为数字值。这可能会提示您问题可能出在哪里。
  • 另外,使用ActivatedRoute.snapshot时要小心。当 URL 中唯一的更改是当前路由的参数值时,Angular 被允许(并且通常确实)重用您的组件,并且您的组件不会收到这些更改的通知。最好订阅ActivatedRoute.paramMap。见here
  • 我添加了一个小的更新来解决我遇到的真正问题

标签: angular typescript forms


【解决方案1】:

你有一个静态值,但你有一个返回角色和权限的服务。

//your service, I imagine more or less 
//I use an unique service, perhafs you use two services

getPermissions(){
   return httpClient.get("yoururl/api/permissions");
}
getManagers(){
   return httpClient.get("yoururl/api/managgers");
}
getRole(id){ //(*)
   return httpClient.get("yoururl/api/role/"+id);
}

//(*) from your another question, if you has a function that return all the roles 
//you can has in your service a "cache" of roles

import {of} from 'rxjs'
import {tap,map} from 'rxjs/operators'
allRoles:any[]
getRole(id){ //(*)
   if (this.allRoles) //If exist, use "of" rxjs operator to return an observable of role
      return of(this.allRoles.find(x=>x.id==id)

   //else get all roles
   return httpClient.get("yoururl/api/getAllRoles").pipe(
      tap(res=>this.allRoles=res), //<--use tap to store in the variable the result
      map(res=>res.find(x=>x.id==id))  //<--use map to return only the role with id
   )
}
//be careful!!!!, if we "cache" the allRoles, rememeber after you edit a role
//"clean" de caché using:
        this.allRoles=null
//else you always received the caché roles

//similar, create a new variables "permisions" and "managers" to "cache"
//so the functions becomes
permisions:any[];
managers:any[];

getPermissions(){
   if (this.permisions)
       return of(this.permisions);
   return httpClient.get("yoururl/api/permissions").pipe(
      tap(res=>this.permisions=res));
}

//and
getManagers(){
   if (this.managers)
       return of(this.managers);
   return httpClient.get("yoururl/api/managgers").pipe(
       tap(res=>this.managers=res))
   )
}

(*) 简单的点击操作符接收到的值用响应做“某事”——通常它用于“记录”或“缓存”

您会看到,要创建 FormGroup,您需要获取“role”、“permissions”和“managers”的值。

所以我们将在 ngOnInit 中完成all。如何获得所有可观察的?使用 forkJoin(是的另一个 rxjs 运算符)

如果我们在变量“id”中有我们可以扮演的角色

ngOnInit()
{
   forkJoin([this.roleService.getPermissions(),
            this.roleService.getManagers(),
            this.rolesService.getRole(id)]).subscribe(
              ([permisions,managers,role]:[any[],any[],any])=>{
                  this.permisions=permisions;
                  this.managers=managers;
                  this.role=role;
                  ..here we call to a funciton to create the formGroup..
              })
            )
}

(*)forkjoin 创建一个并行调用所有“调用”的可观察对象,完成后全部返回结果 - 仅在调用独立时使用

好吧,我们没有“id”(因为我们从参数中得到它)所以,从docs 我们

ngOnInit(){
   this.activatedRoute.paramMap.pipe(
     switchMap(params => {
      const id=Number(params.get('id'));
      //here we has the "id"
      return forkJoin([this.roleService.getPermissions(),
                this.roleService.getManagers(),
                this.rolesService.getRole(id)]
    }).subscribe(([permisions,managers,role]:[any[],any[],any])=>{
         ....
       })
  );
}

(*) switchmap "reemplace" 另一个 observable

【讨论】:

  • 感谢@Eliseo 的努力,但我添加了非常小的更新以简化我的小问题
猜你喜欢
  • 2014-05-03
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-27
  • 1970-01-01
相关资源
最近更新 更多