1
votes

I want to create a component that provides a list of selections to the user but allows only one selection to be made at any given time. The functionality of the mat-radio-group seems to fit that bill the best, but I don't want the actual radio button to be rendered next to the labels within my radio group. I want to expand the label and make any (change) event fire from a click event on the label itself.

What is the least "hacky" way to eliminate the radio buttons from my radio group, while keeping the labels as they were?

1

1 Answers

1
votes

you can also make a custom form control. The idea is that has a .html like

<select-component [(ngModel)]="valor">
    <div select value="1">One</div>
    <div select>Two</div>
</select-component>

We are going to make a directive that the selector was [select]

@Directive({
  selector: '[select]',
})
export class SelectDirective implements AfterViewInit {
  @Input('value')value:any;
  control:any;
  @HostBinding('class.selected') 
  get isSelected(){
    return this.control && this.control.value==this.value?true:undefined
    }
  @HostBinding('class.select')setClass(){return true}
  @HostListener('click') onclick() {
    console.log(this.value);
    if (this.control)
      this.control.setValue(this.value)
  }
  constructor(private el:ElementRef){}

  ngAfterViewInit()
  {
      this.value=this.value ||this.el.nativeElement.innerHTML
  }
}

See that, in ngAfterViewInit we give value to this.value as the innerHTML of the div case you has not defined the value There're two class binding, one .select -this alow us give .css to our component from app.main.component, one .selected, when the div was "selected".

The SelectComponent is a tipical custom form control, the "interesting" is that, in ngAfterViewInit, we ask about the "select" directive inside to allow comunicate the directive and the component

@Component({
  selector: 'select-component',
  template: `<ng-content></ng-content>`,
   providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SelectComponent),
      multi: true
    }

  ]
})
export class SelectComponent implements ControlValueAccessor,AfterViewInit  {
  @ContentChildren(SelectDirective)selects:QueryList<SelectDirective>;
  value:any;
  disabled:boolean=false;
  onChange:any;
  onTouched:any;

   writeValue(value: any[]|any): void {
    this.value=value;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled=isDisabled
  }

  ngAfterViewInit()
  {
    this.selects.forEach(x=>{
      x.control=this
    })
  }
  setValue(value)
  {
    this.value=value
    this.onChange(value)
  }
}

And, voila!, the stackblitz