从服务数据设置用户价值到FormGroup

发布于 2025-02-08 05:35:47 字数 2745 浏览 2 评论 0原文

对于我的Angular项目,我有一个用户配置文件,我想将用户值放在表单控件中。 我尝试了很多事情,但是没有我想要的结果 我想从我的服务中动态设置用户的值。

这是我的form.html

<form [formGroup]="signupForm">
    <div class="container">
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Nom :</label>
            <div class="d-flex align-items-center">
                <input type="text" class="form-control" formControlName="lastname">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Prenom :</label>
            <div class="d-flex align-items-center">
                <input type="text" class="form-control" formControlName="firstname">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Email :</label>
            <div class="d-flex align-items-center">
                <input type="email" class="form-control" formControlName="email" id="exampleInputEmail1" aria-describedby="emailHelp">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <button type="submit" class="btn btn-primary">Sauvegarder</button>
    </div>
</form>

和我的表单

me!: Me
signupForm: FormGroup = new FormGroup({})

constructor(private meService: MeService,  private fb: FormBuilder,) {
  this.CurrentUser()
}

CurrentUser(){
  this.meService.me().subscribe(
    result => {
      this.me = result
    }
  ) 
}
get lastname(): FormControl {
  return this.signupForm.get('lastname') as FormControl;
}

get firstname(): FormControl {
  return this.signupForm.get('firstname') as FormControl;
}

get email(): FormControl {
  return this.signupForm.get('email') as FormControl;
}

ngOnInit(): void {
  this.signupForm = this.fb.group({
    lastname: [
      this.me.lastname,
      [
        Validators.required,
        Validators.maxLength(30),
        Validators.minLength(2),
        Validators.pattern("^[a-zA-Z éèàâëê'-]+$"),
      ]
    ],
    firstname: [
      this.me.firstname,
      [
        Validators.required,
        Validators.maxLength(30),
        Validators.minLength(2),
        Validators.pattern("^[a-zA-Z éèàâëê'-]+$"),
      ]
    ],
    email: [
      this.me.email,
      [
        Validators.required,
        Validators.email,
      ],
    ],
  })
}

。 错误错误:找不到名称的控件:'lastname' 错误错误:找不到名称的控件:'FirSname' 错误错误:找不到名称的控件:“电子邮件”

如何处理?请

For my Angular Project I have a user profile and i want to put values of user in Form control.
I've tried many things but in don't have the result I want
I want to set values of User dynamically from my service

Here's my form.html

<form [formGroup]="signupForm">
    <div class="container">
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Nom :</label>
            <div class="d-flex align-items-center">
                <input type="text" class="form-control" formControlName="lastname">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Prenom :</label>
            <div class="d-flex align-items-center">
                <input type="text" class="form-control" formControlName="firstname">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <div class="form-group mb-5">
            <label for="exampleInputEmail1">Email :</label>
            <div class="d-flex align-items-center">
                <input type="email" class="form-control" formControlName="email" id="exampleInputEmail1" aria-describedby="emailHelp">
                <i class="fa-solid fa-lock pl-3"></i>
            </div>
        </div>
        <button type="submit" class="btn btn-primary">Sauvegarder</button>
    </div>
</form>

And my form.ts

me!: Me
signupForm: FormGroup = new FormGroup({})

constructor(private meService: MeService,  private fb: FormBuilder,) {
  this.CurrentUser()
}

CurrentUser(){
  this.meService.me().subscribe(
    result => {
      this.me = result
    }
  ) 
}
get lastname(): FormControl {
  return this.signupForm.get('lastname') as FormControl;
}

get firstname(): FormControl {
  return this.signupForm.get('firstname') as FormControl;
}

get email(): FormControl {
  return this.signupForm.get('email') as FormControl;
}

ngOnInit(): void {
  this.signupForm = this.fb.group({
    lastname: [
      this.me.lastname,
      [
        Validators.required,
        Validators.maxLength(30),
        Validators.minLength(2),
        Validators.pattern("^[a-zA-Z éèàâëê'-]+
quot;),
      ]
    ],
    firstname: [
      this.me.firstname,
      [
        Validators.required,
        Validators.maxLength(30),
        Validators.minLength(2),
        Validators.pattern("^[a-zA-Z éèàâëê'-]+
quot;),
      ]
    ],
    email: [
      this.me.email,
      [
        Validators.required,
        Validators.email,
      ],
    ],
  })
}

And i'm getting those errors :
ERROR Error: Cannot find control with name: 'lastname'
ERROR Error: Cannot find control with name: 'firsname'
ERROR Error: Cannot find control with name: 'email'

How can I handle this ? please

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如果没有你 2025-02-15 05:35:47

我怀疑的初始错误是因为您首先将FormGroup定义为一个空对象,因此它没有这些值。至少设置某种骨骼可能会解决这些骨骼。如果您要在一个突破点中放置一个损坏,您会看到它一直被打击了,所以很可能是在加载时间之前,在表格有机会水合之前,您正在尝试获取尚不存在的控件。

signupForm: FormGroup = new FormGroup({
        firstname: new FormControl(),
        lastname: new FormControl(),
        email: new FormControl()
    })

相反,最好将其定义为Ingipform:FormGroup,然后在Getter本身中检查未定义。例如:

get email(): FormControl {
  return this.signupForm?.get('email') as FormControl;
}

要记住的另一件事是,您想您正在提出的是API请求。该代码并没有真正等待它完成,也不会阻止它,因此更合适的事情是在获得结果构建后构建实际表格。

this.meService.me().subscribe(
    (result: Me) => {
      if(result) { 
         this.me = result

         //build your form here.
      }         
    }
  ) 

The initial errors I suspect are because you first define your FormGroup as an empty object, thus it doesn't have those values. Setting at least some sort of skeleton for it would probably fix those. getters are fired constantly, if you were to put a break point in one you would see that it keeps getting hit all the time, so odds are that at load time before the form had a chance to be hydrated yet, you are trying to get a control that doesn't exist yet.

signupForm: FormGroup = new FormGroup({
        firstname: new FormControl(),
        lastname: new FormControl(),
        email: new FormControl()
    })

Conversely, it would probably be better to just define it as signupForm: FormGroup and then check for undefined in the getter itself. Ex:

get email(): FormControl {
  return this.signupForm?.get('email') as FormControl;
}

Another thing to keep in mind is that you are making, what I suppose, is an API request. The code doesn't really wait for it to be complete, it is not blocking, so a more appropriate thing to do would be to build your actual form after you get the results build.

this.meService.me().subscribe(
    (result: Me) => {
      if(result) { 
         this.me = result

         //build your form here.
      }         
    }
  ) 
南笙 2025-02-15 05:35:47

我知道这个问题已经有一个答案,但是我会尝试给出一个更紧凑的解决方案,我认为这个问题自从从服务中检索和解析数据到表单控件以来应该具有更高的评分,这是一个非常普遍的情况,该网站上没有类似的问题。我已经使用Angular版本7和8测试了以下解决方案,但它也应该与不同的版本一起使用。

假设服务通过服务检索的数据具有给定的格式:

{
  lastname: string,
  firstname: string,
  email: string
}

您可以简单地创建遵循此结构的表单(就像您一样)

this.formItem = this.formBuilder.group({
  lastname: [''], // here validators and so on
  firstname: [''],
  email: ['']
});

这里重要的是,对于每个简单字段,您都使用
formControl,对于一个对象一个formgroup和一个数组的formarray。

然后,在组件中,您可以简单地编写类似的内容:

this.meService.me().subscribe(
    (result: Me) => {
      if(result) { 
         this.formItem.setValue(result);
      }         
    }
  )

将正确填充表单。只要您知道要检索的数据的结构,就可以对各种数据使用此方法。 无论如何都有一个重要的例外,如果您要检索数组,则必须事先知道数组的长度,这是因为setValue(...) formarray的代码>。这是这种方法的当前实现:

setValue(value, options = {}) {
        this._checkAllValuesPresent(value);
        value.forEach((newValue, index) => {
            this._throwIfControlMissing(index);
            this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
        });
        this.updateValueAndValidity(options);
    }

您可以看到通过您传递的对象的方法迭代,并且可以调用this.at.at(index),此时,如果您声明了一个带有一个元素的FormArray,但是您有一个具有更多元素的对象,您将获得一个例外。我认为这种行为非常烦人,因此我创建了一个自定义的formarray类,该类能够在设置值之前调整控制器大小。当然,这是一个基本的解决方案,但我希望它可以是克服这一限制的好起点。

import {
  AbstractControl,
  AbstractControlOptions,
  AsyncValidatorFn,
  FormArray,
  FormBuilder,
  ValidatorFn
} from "@angular/forms";

export class DynamicFormArrayControl extends FormArray {

  constructor(controls: AbstractControl[], private fb: FormBuilder, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null) {
    super(controls, validatorOrOpts, asyncValidator);
  }

  resize(value: any[]) {
    value.forEach((newValue, index) => {
      if (typeof newValue === 'object'){
        this.push(this.fb.group(newValue));
      } else if (Array.isArray(newValue)) {
        this.push(new DynamicFormArrayControl([], this.fb));
      } else {
        this.push(this.fb.control({}));
      }
    });
  }
  setValue(value: any[], options?: { onlySelf?: boolean; emitEvent?: boolean }) {
    this.resize(value);
    super.setValue(value, options);
  }
}

// in your component
formItem = this.formBuilder.group({
    lastName: [''],
    firstName: [''],
    email: [''],
    adresses: new DynamicFormArrayControl([], this.formBuilder), // let's say you need this array (an array of strings for example)
  });

  ngOnInit(): void {
    // as you can see no changes here
    this.meService.me().subscribe(
(result: Me) => {
  if(result) { 
     this.formItem.setValue(result);
  }         
}


}

I know that this question has already an answer, but I'll try to give a more compact solution, I think that this question should have an higher rating since retrieving and parsing data from a service to a form control is a very common scenario and there are not similar questions on this website. I've tested the following solution with angular version 7 and 8, but it should work also with different versions.

Assuming that the data retrieved by the service has the given format:

{
  lastname: string,
  firstname: string,
  email: string
}

you can simply create a form that follows this structure (as you did)

this.formItem = this.formBuilder.group({
  lastname: [''], // here validators and so on
  firstname: [''],
  email: ['']
});

Here the important thing is that for every simple field you use a
FormControl, for an object a FormGroup and a FormArray for an array.

then in your component you can simply write something like this:

this.meService.me().subscribe(
    (result: Me) => {
      if(result) { 
         this.formItem.setValue(result);
      }         
    }
  )

and the form will be correctly filled. You can use this approach for every kind of data as long as you know the structure of the data you are retrieving. There is anyway an important exception, if you are retrieving an array you have to know in advance the length of the array, this is because of the way the setValue(...) of the FormArray is implemented. Here it is the current implementation of such a method:

setValue(value, options = {}) {
        this._checkAllValuesPresent(value);
        value.forEach((newValue, index) => {
            this._throwIfControlMissing(index);
            this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
        });
        this.updateValueAndValidity(options);
    }

as you can see the method iterates over the object you pass and it does a call to this.at(index), at this point if you declare a FormArray with one element, but you have an object with more elements you will get an exception. I think that this behaviour is very annoying so I've created a custom FormArray class that is capable of resize the controller before to procede to setting the value. Of course this is a basic solution, but I hope it can be a good starting point to overcome this limitation.

import {
  AbstractControl,
  AbstractControlOptions,
  AsyncValidatorFn,
  FormArray,
  FormBuilder,
  ValidatorFn
} from "@angular/forms";

export class DynamicFormArrayControl extends FormArray {

  constructor(controls: AbstractControl[], private fb: FormBuilder, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null) {
    super(controls, validatorOrOpts, asyncValidator);
  }

  resize(value: any[]) {
    value.forEach((newValue, index) => {
      if (typeof newValue === 'object'){
        this.push(this.fb.group(newValue));
      } else if (Array.isArray(newValue)) {
        this.push(new DynamicFormArrayControl([], this.fb));
      } else {
        this.push(this.fb.control({}));
      }
    });
  }
  setValue(value: any[], options?: { onlySelf?: boolean; emitEvent?: boolean }) {
    this.resize(value);
    super.setValue(value, options);
  }
}

// in your component
formItem = this.formBuilder.group({
    lastName: [''],
    firstName: [''],
    email: [''],
    adresses: new DynamicFormArrayControl([], this.formBuilder), // let's say you need this array (an array of strings for example)
  });

  ngOnInit(): void {
    // as you can see no changes here
    this.meService.me().subscribe(
(result: Me) => {
  if(result) { 
     this.formItem.setValue(result);
  }         
}

)
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文