I have 2 arrays. I'm implementing an Angular drag drop and I want to use FormArray to save the array in which the element was dropped into.
The problem is that I can't apply formcontrol to the div as it gives an error
Error: No value accessor for form control with name: 'language'
Here is the html
<div>
<div class="example-container">
<h2>Selected Languages</h2>
<div
cdkDropList
#todoList="cdkDropList"
[cdkDropListData]="anotherarray"
[cdkDropListConnectedTo]="[doneList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
formControlName="language">
<div class="list-group-item list-group-item-action " *ngFor="let item of anotherarray" cdkDrag>
{{item}}
</div>
</div>
</div>
<div class="example-container">
<h2>Available Languages</h2>
<div
cdkDropList
#doneList="cdkDropList"
[cdkDropListData]="testingarray"
[cdkDropListConnectedTo]="[todoList]"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="list-group-item list-group-item-action " *ngFor="let item of testingarray" cdkDrag>{{item}}</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary my-2" translate>saveButtonLabel
<fa-icon *ngIf="saveIcon" [icon]="saveIcon" [spin]="saveIcon.iconName === 'spinner'"></fa-icon>
</button>
</form>
The Angular Material drag / drop API has a moveItemInArray function as seen here
This only supports regular arrays but as per pierNik's answer here on StackOverflow, you can replicate the functionality for a FormArray with the following function:
import { FormArray } from '@angular/forms';
/**
* Moves an item in a FormArray to another position.
* @param formArray FormArray instance in which to move the item.
* @param fromIndex Starting index of the item.
* @param toIndex Index to which he item should be moved.
*/
export function moveItemInFormArray(
formArray: FormArray,
fromIndex: number,
toIndex: number
): void {
const dir = toIndex > fromIndex ? 1 : -1;
const item = formArray.at(fromIndex);
for (let i = fromIndex; i * dir < toIndex * dir; i = i + dir) {
const current = formArray.at(i + dir);
formArray.setControl(i, current);
}
formArray.setControl(toIndex, item);
}
Then in your calling code you pass the formArray in place of a normal array.
get formControls(): FormArray {
return this.form.get('arrayName') as FormArray;
}
constructor() {
this.form = this.formBuilder.group({
arrayName: this.formBuilder.array([]),
});
}
drop(event: CdkDragDrop<string[]>) {
moveItemInFormArray(
this.formControls,
event.previousIndex,
event.currentIndex
);
}
See working Stackblitz here
Currently we cannot use a formControl with Angular Drag and Drop as it works with div and we cannot add formContol to it. Therefore we need to use the event cdkDropListDropped to update our model manually every time an item has been dropped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With