10

I've built a custom input component with ControlValueAccessor and it works great to add tags as selections. (Stackblitz)

My problem is:

  1. when I implement the component within a form (cities & states controls)
  2. add values to both controls by selecting some options
  3. submit the form
  4. sometimes the control value is an array of selected tags (as expected)
  5. other times it's an actual FormArray object

Here is a screenshot of two of the same component's values after submitting the angular form. One is an array of objects (expected) the other is an actual FormArray object which .value property contains the array of objects!

enter image description here

Here is some code of how it works in case you don't want to visit StackBlitz.

The custom control is implemented like this.

this.form = this.fb.group({
  tags: this.fb.array([])
});

When the user selects a dropdown item or hits enter the object is saved like this:

get tagsArray(): FormArray { return this.form.get('tags') as FormArray; }
...
this.tagsArray.push(new FormControl(value));
this.onChange(this.tagsArray); // update controller value

You could replicate this by implementing the component in my StackBlitz in a formGroup just like this (also in my StackBlitz):

Form Init

public form: FormGroup = this.fb.group({
    states: [],
    cities: []
});

Template

<input-tags formControlName="cities" label="Cities" [typeAhead]="cities" [displayKeys]="['name']" filterKeys="['name']"></input-tags>
<input-tags formControlName="states" label="States" [typeAhead]="states" [displayKeys]="['name']" filterKeys="['name']"></input-tags>

but the question is:

When is Angular's FormArray a traditional array and when is it a FormArray Array like object?

0

1 Answer 1

3
+50

FormArray object is being created when you create a control instance using new FormArray([]) or formBuilder.array([]).

However, if you apply a FormControl instance to class with ControlValueAccessor methods it will write either FormControl or FormGroup (if you want to work with provided by Angular form objects) to the value of control you have passed.

Thus, in first case you get a FormArray object and in second case you can get either regular JS types (object, array, string etc.) or FormGroup/FormControl.

If you want more expanded answer specific to your case the code sample is required because your implementation may cause transforming array to FormArray at some point.

Update #1

If we change a valueChanges from users to form we can see that this form is kind of broken, because .value gives us another FormArray instead of just Array.

enter image description here

Also, I've checked the implementation and there is nowhere you can get regular array in there. However, custom control is implemented wrong IMHO, since you should the value on .value instead of FormArray or whatever similar to this.

Therefore, if you can change the implementation of this control I would suggest you do that. I do it in way of

registerOnChange(fn: any): void {
  this.tagsArray.valueChanges.subscribe(fn);
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks @Sergey, this is insightful. But this control is implemented exactly the same way twice in the same form and they each sometimes have [] value and sometimes have FormArray{} value, as the value screenshot shows.
@BenRacicot in that case I would advise you to inspect your code using IDE debugging tool to see where your value transforms. Just make breakpoints everywhere the value is being assigned to control and you should find it.
Yes, initial value is an array, patch values are arrays but selecting an option creates FormArray value. Any values added go through the same addTag method. That's why this doesn't make sense. Can you explain more about the registerOnChange refactor you recommend? Thanks for this BTW.
@BenRacicot that's just a basic method of ControlValueAccessor which is used to define the function which should get the values to assign them to the main form. More about it you can read here angular.io/api/forms/ControlValueAccessor
@BenRacicot personally I see no point in pushing FormArray objects into your main form as it kind of breaks the logic and causing some problems. When I implement these ControlValueAccessor I work only with simple values (meaning not AbstractControl descendants) and everything works pretty fine.
|

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.