2

I've created a reusable checkbox component, with the purpose of selecting a single value to be added as a string, not boolean. The problem is the value is not binded in the component which uses the checkbox component, only on onChangeCategory() method. What should I do?

checkbox.html:

<div class="form-check" *ngFor="let cat of options">
              <input class="form-check-input"  (change)="onChangeCategory(cat, $event.target.checked)"name="{{ cat }}" type="checkbox" id="{{cat}}">
              <label class="form-check-label" for="{{cat}}">
                {{cat}}
              </label>
            </div>

checkbox.ts:

@Input() name: string;
@Input() options: string[];
@Input() selectedValue: string;

onChangeCategory(option: string, isChecked: boolean){ // Use appropriate model type instead of any
    if(isChecked) {
      this.selectedValue = option;
    }
    else {
      this.selectedValue = this.options[0];
    }

  }

the component using the checkbox - html:

<app-checkbox [options]=sexOptions
              [selectedValue]=selectedValue>
</app-checkbox>

the component using the checkbox - ts:

sexOptions: string[] = ['Male', 'Female'];
selectedValue: string; //this should take the value from the checkbox

2 Answers 2

1

Try to use 'BANANA IN A BOX' approach where your @Input is also @Output, see this article for example.

HTML

<app-checkbox [options]=sexOptions
              [(selectedValue)]=selectedValue>
</app-checkbox>

TS

export class CheckboxComponent {
  @Input() name: string;
  @Input() options: string[];
  @Input() selectedValue: string;
  @Output() selectedValueChange = new EventEmitter<string>();

  private toggle: {[key: string]: string};

  ngOnInit() {
    // I aasume we have only 2 string options
    this.toggle = {
      [this.options[0]]: this.options[1],
      [this.options[1]]: this.options[0]
    };
  }

  onChangeCategory(option: string, isChecked: boolean) {
    this.selectedValue = isChecked ? option : this.toggle[option];
    this.selectedValueChange.emit(this.selectedValue);
  }
}

I created a STACKBLITZ to play with. In my example I added a default value, if it is not required, just do not initialize it. Also I changed checks behavior to have only one single value (kind of radio options)

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this is the answer I was looking for since I can bind it to my FormControl element. One more thing I want to know, is possible to bind it directly to a FormControl value (sex: FormControl ) inside a FormGroup (pacientForm: FormGroup), without explicitly assign this.pacientForm.value.sex = this.selectedValue in the parent component? Something like using @Input() group: FormGroup, @Input() controlName: string, this.selectedValueChange.emit(this.controlName)? Thanks.
I think what you need is custom angular form element (which will work as regular FormControl in both reactive and template driven forms). See example of it here: netbasal.com/…
Actually in my case it can be much simple that that, I only need to bind the fomrControlName to the selected option, but simply applying the option from event emitter to the formControName won't work.
0

Have you check about [@Output][1]?

You can use it to trigger event between component and pass its values. In your case you can do:

@Input() name: string;
@Input() options: string[];
@Input() selectedValue: string;

@Output() change: EventEmitter<string> = new EventEmitter() 

onChangeCategory(option: string, isChecked: boolean){ // Use appropriate model type instead of any
  if(isChecked) {
    this.selectedValue = option;
  }
  else {
    this.selectedValue = this.options[0];
  }

  this.change.emit(this.selectedValue)
}

And when you use that component within the parent you want to bind the value, you do

<app-checkbox-component (change)="onChange($event)"></app-checkbox-component>

And into your parent .ts file

onChange(value) {
   console.log(value)
}

1 Comment

It works, but I want the value to be binded in a FormGroup (pacientForm: FormGroup) with a FormControl inside it (sex: new FormControl('', [])) from the parent component. If I'm using this.pacientForm.value.sex = value, on the onChange(value) method it's not binded when I'm doing the submit.

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.