kerpekri
kerpekri

Reputation: 377

Reactive forms - On valueChanges subscribe / update checkbox options

What I am trying to achieve is something like this, I have a result set with three options bmw, audi and opel, in the select I can only select one of the options, but if needed the user can still select not selected options(checkboxes) Result set:

cars = [
    { id: 1, name: 'bmw' },
    { id: 2, name: 'audi' },
    { id: 3, name: 'opel' }
];

Flow:

For example, lets say in the select I have selected bmw, so after the select I need to show two checkboxes, because audi & opel is still available options. If I change bmw to something else I also need to update the checkboxes to show those values what's not selected in the select.

form:

this.firstStepForm = this.fb.group({
  cars: [''], // select
  models: this.fb.array([]) // checkboxes
});

Setup checkboxes:

private setupControls(details: any): void {
let control = <FormArray>this.firstStepForm.controls.models;

details.forEach(x => {
  control.push(this.fb.group({
    id: x.id,
    name: x.name
  }))
})

Subscribe for changes:

this.firstStepForm.get('cars').valueChanges.subscribe((carId: number)

A simple example - stackblitz

At the moment, I don't really understand how to get the index of the specific car(selected in the select) and update/remove checkboxes.

Result:

  1. checkboxes only show the options that are not selected in the select
  2. if I change the selected value to something else, I need to update checkboxes to show options what's left from the result set.

Comments:

Maybe I don't even need to use removeAt(FormArray), but just a simple underscoreJs _filter & filter out based on the id? But how can I filter out FormArray based on specific value(:id)?

let magic = _.filter(arr, function (num) { return num != carId });

console.log('magic: ', magic);

Upvotes: 0

Views: 3507

Answers (1)

Lia
Lia

Reputation: 11982

try:

export class AppComponent implements OnInit {
  cars = [
    { id: 1, name: 'bmw' },
    { id: 2, name: 'audi' },
    { id: 3, name: 'opel' }
  ];
  firstStepForm: FormGroup;
  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.buildFirstStepForm();
    this.firstStepForm.get('cars').setValue(this.cars[0].id);
    this.onChange(this.cars[0].id); // initial first item select
  }

  onChange(e){
    let arr = this.cars.filter(item => item.id != e);
    this.models.controls = [];
    this.setupControls(arr)
  }

  get models(): FormArray {
    return <FormArray>this.firstStepForm.controls.models;
  }

  private buildFirstStepForm(): void {
    this.firstStepForm = this.fb.group({
      cars: [''],
      models: this.fb.array([])
    });
  }

  private setupControls(details: any): void {
    details.forEach(x => {
      this.models.push(this.fb.group({
        id: [x.id],
        name: [x.name]
      }))
    })
  }
}

html:

<form [formGroup]="firstStepForm" (ngSubmit)="submit()">
    <p>Select:</p>
    <select formControlName="cars" (change)="onChange($event.target.value)">
        <option *ngFor="let car of cars; let i = index" [value]="car.id">
            {{car.name}}
        </option>
    </select>
  <br>
  <br>
  <br>
  <p>Checkboxes:</p>
  <div class="form-check" *ngFor="let type of models.controls; let i = index">
    <label formArrayName="models">
      <input type="checkbox">{{type.value.name}}
    </label>
  </div>
</form>

DEMO

Upvotes: 1

Related Questions