Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the ideal way to sort a FormArray object in Angular 2+?

I have a formArray which consist of multiple form groups. I need to sort the array dynamically based on a boolean field present in each of the form group in the array.

The boolean field is a checkbox and at any given point of time only one checkbox can be checked (mimics radio button). So when a checkbox is clicked I need to sort the formArray based on the one that is selected.

I know the documentation suggests not to mess with the AbstractControls[] present in the formArray, so what would be the ideal way to dynamically sort the array ?

I have tried to slice the array and set the controls back into the formArray but I keep getting an error "Must supply a value for form control with name: 'primaryIndicator'."

const abstractControls = this.formArray.controls
          .slice()
          .sort((a, b) => {
            return (a as FormGroup).get('primaryIndicator').value ? -1 : (b as FormGroup).get('primaryIndicator').value ? 1 : 0;
          });
        this.formArray.setValue(abstractControls);

If this is not the right way, what would be the best approach to solve such a scenario ?

like image 366
Adnan Mamajiwala Avatar asked Mar 08 '18 03:03

Adnan Mamajiwala


People also ask

How does angular define FormArray?

First, we need to import the FormArray from the Angular Forms Module. Build a formGroup orderForm using the FormBuilder. We define items as FormArray. We need to capture two fields under each item, the name of the item & description and price.

How is FormArray used in reactive form?

Binding FormArray to Template We use the formArrayName directive to bind the skills form array to the div element. Now the div and anything inside the div element is bound to the skills form array. Inside the div use ngFor to loop through each element of skills FormArray.

How do you set values on FormArray?

FormArray setValue() setValue() sets the value of the FormArray . We need to pass an array that matches the structure of the control. Create a sample FormArray . myFormArray = new FormArray([ new FormControl(), new FormControl(), new FormControl() ]);


3 Answers

I do not think it would be the best way, but get the values from formarray, do whatever you want with it and patch them back.

var myArray = this.formArray.value;
//do sorting here with myArray.sort 
this.formArray.patchValue(myArray)

Do not change the length and schema of this.formArray. Patchvalue can only patch values, if they have same structure.

like image 55
Lorfme Avatar answered Sep 25 '22 12:09

Lorfme


It worked for me. I did something like this with a one-liner

this.names.patchValue(this.names.value.sort((a, b) => a.name.localeCompare(b.name)));

like image 34
user2771575 Avatar answered Sep 23 '22 12:09

user2771575


I already had an array of sorted values and use lodash's _.sortBy method like this:

const orderedTitles: Array<string> = ['title1', 'title2', 'title3'];
const pagesFormArray: FormArray = (this.form.get('pages') as FormArray);
pagesFormArray.controls = _.sortBy(pagesFormArray.controls, (control) => {
  return _.indexOf(orderedTitles, control.value.title'
});

The trouble I had with using @Lorfme's answer, was that I was extending the base Angular form controls and setting additional properties on my classes. Like this:

class MyNewFormArray extends FormArray {
  private additionalStuff;

  constructor(formArgs, additionalStuff) {
    super(formArgs);
    this.additional = additionalStuff;
  }

  someMethod() {
    return this.additionalStuff;
  }
}
like image 22
Ian Jamieson Avatar answered Sep 25 '22 12:09

Ian Jamieson