最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do i display a FormArray of GroupLists? - Stack Overflow

programmeradmin6浏览0评论

I am trying to make an interactive form that on each row lists an item together with a remove button (called verwijderen in my example). These items are retrieved from the database and each instantiated as a custom object called LaborPeriod.

These objects are then transformed into FormGroup object and then added to a FormArray. The definition of this formgroup is the following:

  let formGroup = this.fb.group({
    id: this.account.laborperiods[i].id,
    beginDate: this.account.laborperiods[i].beginDate,
    endDate: this.account.laborperiods[i].endDate,
    hours: this.account.laborperiods[i].hours,
    account: this.account.laborperiods[i].account
  })
  if(!this.laborPeriodArray){
    this.laborPeriodArray = new FormArray([])
  }
  this.laborPeriodArray.push(formGroup)
}

The definition of the laborPeriodArray in the main FormGroup is also laborPeriodArray. The main FormGroup looks like the following:

  constructor(private fb: FormBuilder,
              private route: ActivatedRoute,
              private router: Router,
              private accountService: AccountService) {
    this.title = "Account aanpassen";
    //console.log(this.account.enabled + " : " + this.account.role)
    this.accountUpdateForm = this.fb.group({
      name: [''],
      username: ['', [Validators.required, Validators.email]],
      status: '',
      permission:'',
      laborPeriodArray:this.fb.array([])
    });
  }

The entire ponent looks like this: Here you can see that laborPeriodArray gets initialized in the onInit method.

  constructor(private fb: FormBuilder,
              private route: ActivatedRoute,
              private router: Router,
              private accountService: AccountService) {
    this.title = "Account aanpassen";
    //console.log(this.account.enabled + " : " + this.account.role)
    this.accountUpdateForm = this.fb.group({
      name: [''],
      username: ['', [Validators.required, Validators.email]],
      status: '',
      permission:'',
      laborPeriodArray:this.fb.array([])
    });
  }

  ngOnInit(): void {
    let formGroupArray: FormGroup[] = [];
    this.route.paramMap
      .switchMap((params: ParamMap) =>
        this.accountService.getAccount(params.get("id")))
      .subscribe(account => {
        this.account = account;
        for(let i=0; i < account.laborperiods.length; i++){
          let formGroup = this.fb.group({
            id: this.account.laborperiods[i].id,
            beginDate: this.account.laborperiods[i].beginDate,
            endDate: this.account.laborperiods[i].endDate,
            hours: this.account.laborperiods[i].hours,
            account: this.account.laborperiods[i].account
          })
          if(!this.laborPeriodArray){
            this.laborPeriodArray = new FormArray([])
          }
          this.laborPeriodArray.push(formGroup)
        }
        console.log("laborPeriod" + JSON.stringify(this.laborPeriodArray.length))

        this.ngOnChanges();
      });
  }

  ngOnChanges(): void {
    if (this.account !== undefined) {
      this.accountUpdateForm.reset({
        name: this.account.name,
        username: this.account.username,
        status: this.account.enabled,
        permission: this.account.admin,
        laborPeriodArray: this.laborPeriodArray
      });
    }
  }

All the FormGroup items are added but not displayed. The rows are blank. This is the relevant snippet from my HTML page

<table class="table table-hover">
      <thead>
      <tr>
        <th>Begin datum</th>
        <th>Eind datum</th>
        <th>Aantal uren</th>
        <th>Actie</th>
      </tr>
      </thead>
      <tbody>
      <tr formArrayName="laborPeriodArray" *ngFor = "let laborperiod of laborPeriodArray.controls; let i = index" [formGroupName]="i">
        <td formControlName="beginDate">{{laborperiod.value.get('beginDate') | date:'yyyy-MM-dd'}}</td>
        <td formControlName="endDate">{{laborperiod.value.get('endDate') | date:'yyyy-MM-dd'}}</td>
        <td formControlName="hours">{{laborperiod.value.get('hours')}}</td>
        <button type="button" class="btn btn-default">
          <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
          Verwijderen
        </button>
      </tr>

This is giving me the browser error ERROR Error: Cannot find control with unspecified name attribute but I am specifying the formControlName for each td row. So I don't understand what is causing the error. Furthermore I would also like to know how I can link the Remove button to the data corresponding to each row. I take it I have to use the index I for this but i'm not sure.

EDIT:

After applying AJT_82's solution I still don't have it working. It appears to have something to do with the database retrieved data itself. When I add the example account array of AJT_82 to my ngOnInit() like so:

  account1 = { laborperiods: [{ id: 1, hours:11 }, { id: 2, hours:22 }, { id: 3, hours:33 }] }

  ngOnInit(): void {
    this.route.paramMap
      .switchMap((params: ParamMap) =>
        this.accountService.getAccount(params.get("id")))
      .subscribe(account => {
        this.account = account;
        for(let i=0; i < account.laborperiods.length; i++){
          let formGroup = this.fb.group({
            id: this.account1.laborperiods[i].id,
            beginDate: this.account.laborperiods[i].beginDate,
            endDate: this.account.laborperiods[i].endDate,
            hours: this.account1.laborperiods[i].hours,
            account: this.account.laborperiods[i].account
          })
          this.laborPeriodArray.push(formGroup)
        }
        console.log(JSON.stringify(account.laborperiods[0].beginDate))
        this.ngOnChanges();
      });
  }

it works but it shows only 3 rows. That's the total length of the example account array.

This is the account class:

export class Account {
  id: number;
  username: string;
  name: string;
  enabled: boolean
  password: string;
  person: Person;
  admin: boolean;
  laborperiods: LaborPeriod[]
  remainingLeaveHours:number;
}

and this is the LaborPeriod class:

export class LaborPeriod{
    id: number
    beginDate: Date
    endDate: Date
    hours: number
    account: Account
}

Is there anything wrong with its field declarations?

I am trying to make an interactive form that on each row lists an item together with a remove button (called verwijderen in my example). These items are retrieved from the database and each instantiated as a custom object called LaborPeriod.

These objects are then transformed into FormGroup object and then added to a FormArray. The definition of this formgroup is the following:

  let formGroup = this.fb.group({
    id: this.account.laborperiods[i].id,
    beginDate: this.account.laborperiods[i].beginDate,
    endDate: this.account.laborperiods[i].endDate,
    hours: this.account.laborperiods[i].hours,
    account: this.account.laborperiods[i].account
  })
  if(!this.laborPeriodArray){
    this.laborPeriodArray = new FormArray([])
  }
  this.laborPeriodArray.push(formGroup)
}

The definition of the laborPeriodArray in the main FormGroup is also laborPeriodArray. The main FormGroup looks like the following:

  constructor(private fb: FormBuilder,
              private route: ActivatedRoute,
              private router: Router,
              private accountService: AccountService) {
    this.title = "Account aanpassen";
    //console.log(this.account.enabled + " : " + this.account.role)
    this.accountUpdateForm = this.fb.group({
      name: [''],
      username: ['', [Validators.required, Validators.email]],
      status: '',
      permission:'',
      laborPeriodArray:this.fb.array([])
    });
  }

The entire ponent looks like this: Here you can see that laborPeriodArray gets initialized in the onInit method.

  constructor(private fb: FormBuilder,
              private route: ActivatedRoute,
              private router: Router,
              private accountService: AccountService) {
    this.title = "Account aanpassen";
    //console.log(this.account.enabled + " : " + this.account.role)
    this.accountUpdateForm = this.fb.group({
      name: [''],
      username: ['', [Validators.required, Validators.email]],
      status: '',
      permission:'',
      laborPeriodArray:this.fb.array([])
    });
  }

  ngOnInit(): void {
    let formGroupArray: FormGroup[] = [];
    this.route.paramMap
      .switchMap((params: ParamMap) =>
        this.accountService.getAccount(params.get("id")))
      .subscribe(account => {
        this.account = account;
        for(let i=0; i < account.laborperiods.length; i++){
          let formGroup = this.fb.group({
            id: this.account.laborperiods[i].id,
            beginDate: this.account.laborperiods[i].beginDate,
            endDate: this.account.laborperiods[i].endDate,
            hours: this.account.laborperiods[i].hours,
            account: this.account.laborperiods[i].account
          })
          if(!this.laborPeriodArray){
            this.laborPeriodArray = new FormArray([])
          }
          this.laborPeriodArray.push(formGroup)
        }
        console.log("laborPeriod" + JSON.stringify(this.laborPeriodArray.length))

        this.ngOnChanges();
      });
  }

  ngOnChanges(): void {
    if (this.account !== undefined) {
      this.accountUpdateForm.reset({
        name: this.account.name,
        username: this.account.username,
        status: this.account.enabled,
        permission: this.account.admin,
        laborPeriodArray: this.laborPeriodArray
      });
    }
  }

All the FormGroup items are added but not displayed. The rows are blank. This is the relevant snippet from my HTML page

<table class="table table-hover">
      <thead>
      <tr>
        <th>Begin datum</th>
        <th>Eind datum</th>
        <th>Aantal uren</th>
        <th>Actie</th>
      </tr>
      </thead>
      <tbody>
      <tr formArrayName="laborPeriodArray" *ngFor = "let laborperiod of laborPeriodArray.controls; let i = index" [formGroupName]="i">
        <td formControlName="beginDate">{{laborperiod.value.get('beginDate') | date:'yyyy-MM-dd'}}</td>
        <td formControlName="endDate">{{laborperiod.value.get('endDate') | date:'yyyy-MM-dd'}}</td>
        <td formControlName="hours">{{laborperiod.value.get('hours')}}</td>
        <button type="button" class="btn btn-default">
          <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
          Verwijderen
        </button>
      </tr>

This is giving me the browser error ERROR Error: Cannot find control with unspecified name attribute but I am specifying the formControlName for each td row. So I don't understand what is causing the error. Furthermore I would also like to know how I can link the Remove button to the data corresponding to each row. I take it I have to use the index I for this but i'm not sure.

EDIT:

After applying AJT_82's solution I still don't have it working. It appears to have something to do with the database retrieved data itself. When I add the example account array of AJT_82 to my ngOnInit() like so:

  account1 = { laborperiods: [{ id: 1, hours:11 }, { id: 2, hours:22 }, { id: 3, hours:33 }] }

  ngOnInit(): void {
    this.route.paramMap
      .switchMap((params: ParamMap) =>
        this.accountService.getAccount(params.get("id")))
      .subscribe(account => {
        this.account = account;
        for(let i=0; i < account.laborperiods.length; i++){
          let formGroup = this.fb.group({
            id: this.account1.laborperiods[i].id,
            beginDate: this.account.laborperiods[i].beginDate,
            endDate: this.account.laborperiods[i].endDate,
            hours: this.account1.laborperiods[i].hours,
            account: this.account.laborperiods[i].account
          })
          this.laborPeriodArray.push(formGroup)
        }
        console.log(JSON.stringify(account.laborperiods[0].beginDate))
        this.ngOnChanges();
      });
  }

it works but it shows only 3 rows. That's the total length of the example account array.

This is the account class:

export class Account {
  id: number;
  username: string;
  name: string;
  enabled: boolean
  password: string;
  person: Person;
  admin: boolean;
  laborperiods: LaborPeriod[]
  remainingLeaveHours:number;
}

and this is the LaborPeriod class:

export class LaborPeriod{
    id: number
    beginDate: Date
    endDate: Date
    hours: number
    account: Account
}

Is there anything wrong with its field declarations?

Share Improve this question edited Nov 17, 2017 at 9:10 Maurice asked Nov 16, 2017 at 11:11 MauriceMaurice 7,41111 gold badges60 silver badges124 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

You cannot have formArrayName on the same element as your iteration and formGroupName, you need to move the formArrayName to an upper level. Also I see no use of the formControlName, as these are not editable fields, and Angular will throw error for this. Also the use of for example...

{{laborperiod.value.get('beginDate') | date:'yyyy-MM-dd'}}

is incorrect, it should be just

{{laborperiod.value.beginDate | date:'yyyy-MM-dd'}}

Assumingly in your code, the variable laberPeriodArray is declared...

this.laborPeriodArray = 
     this.accountUpdateForm.controls.laborPeriodArray as FormArray

since you are referring to this.laborPeriodArray in your code, therefore the following:

if(!this.laborPeriodArray){
  this.laborPeriodArray = new FormArray([])
}

is redundant, you have already declared it in the build of the form as an empty FormArray. But that is just a sidenote :)

All in all, your template should look something like this:

<table formArrayName="laborPeriodArray" >
  <tr *ngFor="let laborperiod of laborPeriodArray.controls; 
      let i = index" [formGroupName]="i">
    <td>{{laborperiod.value.hours}}</td>
  </tr>
</table>

DEMO

Try replacing

laborperiod.value.get('beginDate')

By

laborperiod.value['beginDate']

I also remande that you FormGroup variable to be a Class attribute and not a OnInit() one.

I also remande using ReactiveForms with it's API FormControls.

  • Let me know what happened
发布评论

评论列表(0)

  1. 暂无评论