1

I want to output a form in which one field is an array, and for each element of the array I need to output my inputs.

Component:

userData.contacts = [
{contact_type: "phone", value: "380666666666"},
{contact_type: "email", value: "[email protected]"},
{contact_type: "website", value: "www.good.co"}
];

this.contactInfoForm = new FormGroup ({
          contacts: this.fb.array (userData.contacts)
        });

HTML:

 

<form [formGroup] = "contactInfoForm" novalidate (ngSubmit) = "submit ('contactInfoForm')">
<div formArrayName = "contacts" * ngFor = "let contact of contactInfoForm.get ('contacts'). controls; let i = index;">
              <div formGroupName = "i">
                <label> {{contact.value.contact_type}} </ label>
                <input formControlName = "value">
              </ div>
            </ div>
</ form>

If to deduce in the console the form that there an object with a heap of the data.

 

  asyncValidator: null
controls:
contacts: FormArray
asyncValidator: null
controls: Array (3)
0: FormControl {validator: null, asyncValidator: null, _onCollectionChange: ƒ, pristine: true, touched: false, ...}
1: FormControl {validator: null, asyncValidator: null, _onCollectionChange: ƒ, pristine: true, touched: false, ...}
2: FormControl {validator: null, asyncValidator: null, _onCollectionChange: ƒ, pristine: true, touched: false, ...}
length: 3
__proto__: Array (0)
dirty: (...)
disabled: (...)
enabled: (...)
errors: null
invalid: (...)
length: (...)
parent: (...)
pending: (...)
pristine: true
root: (...)
status: DISABLED
statusChanges: EventEmitter {_isScalar: false, observers: Array (0), closed: false, isStopped: false, hasError: false, ...}
touched: false
untouched: (...)
updateOn: (...)
valid: (...)
validator: null
value: (3) [{...}, {...}, {...}]
valueChanges: EventEmitter {_isScalar: false, observers: Array (0), closed: false, isStopped: false, hasError: false, ...}
_onCollectionChange: ƒ ()
_onDisabledChange: []
_parent: FormGroup {validator: null, asyncValidator: null, _onCollectionChange: ƒ, pristine: true, touched: false, ...}
__proto__: AbstractControl
__proto__: Object
dirty: (...)
disabled: (...)
enabled: (...)
errors: null
invalid: (...)
parent: (...)
pending: (...)
pristine: true
root: (...)
status: DISABLED
statusChanges: EventEmitter {_isScalar: false, observers: Array (0), closed: false, isStopped: false, hasError: false, ...}
touched: false
untouched: (...)
updateOn: (...)
valid: (...)
validator: null
value: {contacts: Array (3)}
valueChanges: EventEmitter {_isScalar: false, observers: Array (0), closed: false, isStopped: false, hasError: false, ...}
_onCollectionChange: ƒ ()
_onDisabledChange: []
__proto__: AbstractControl

I have tried to derive the information in different ways. It does not work. Even if stupidly copy-paste pieces from examples in the Internet. The same problems. The same mistakes.

Error:

 Cannot find control with path: 'contacts -> 0 -> value'

Also tried:

<input [formControlName]="contact.value.value">

Got error:

contacts -> 0 -> 380666666666

3
  • your *ngFor should not be within your formArrayName=... element but one child below. You should ngFor children of formArray. Commented Sep 10, 2018 at 8:05
  • i have tried before. also did not work. but i will try now again Commented Sep 10, 2018 at 8:13
  • not helped. nothing changed. Commented Sep 10, 2018 at 8:25

2 Answers 2

1

You need to provide array of FormControl elements for your contacts, instead of plain array.

const formControlArray = [];
userData.contacts.forEach(contact => {
  formControlArray.push(new FormControl(contact.value));
})

this.contactInfoForm = new FormGroup ({
  contacts: this.fb.array(formControlArray)
});

But, I am not sure the FormArray is the best choice for your use case, since elements must have different names. You can just dynamically add controls this way too:

this.contactInfoForm = new FormGroup({});

userData.contacts.forEach(contact => {
  contactInfoForm.addControl(contact.contact_type, new FormControl(contact.value));
})
Sign up to request clarification or add additional context in comments.

2 Comments

i dont wanna use map or foreach. FormBuilder.array() is standard feature. i wanna use it) but thx.
But you still would would need to wrap your contact data in FormControl. FormArray constructor doesn't support just plain objects.
0

Component:

 userData.contacts = [{
        contact_type: "phone",
        value: "380666666666"
    }, {
        contact_type: "email",
        value: "[email protected]"
    }, {
        contact_type: "website",
        value: "www.good.co"
    }];

    this.contactInfoForm = new FormGroup({
        contacts: this.fb.array([
            ...this.userData.contacts.map(({ contact_type, value }) => {
                return this.fb.group({
                    contact_type,
                    value
                });
            })
        ])
    });

HTML:

 <form [formGroup]="contactInfoForm" novalidate (submit)="submit('contactInfoForm')">
        <div formArrayName="contacts" *ngFor="let contact of contactInfoForm.get('contacts').controls; let i = index;">
            <div [formGroupName]="i" >
                <label>{{ contact.value.contact_type }}</label>
                <input formControlName="value">
            </div>
        </div>
    </form>

Works fine. but i still doesn't like to use map method.

1 Comment

great. I am not sure you can avoid using map or forEach. You need anyway to iterate over your contacts and create multiple FormGroup elements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.