What is a creative way to design a mat-radio-group without traditional radio buttons?

I am looking to create a component that offers users a list of selections with the ability to make only one choice at a time. The mat-radio-group functionality seems to be the best fit for this, but I prefer not to display the actual radio button next to the labels within my group. I would like to extend the label to trigger any (change) event by clicking on the label itself.

What is the most elegant solution to remove the radio buttons from my radio group while maintaining the appearance of the labels?

Answer №1

If you want to create a unique custom form control, consider implementing a custom directive with an HTML structure like this:

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

To achieve this, we will create a directive with the selector [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;
  }
}

In this code snippet, we assign a value to this.value in ngAfterViewInit if it is not previously defined. We also have two class bindings for styling purposes: one for the component and another when the div is selected.

The SelectComponent acts as a custom form control. In ngAfterViewInit, we link the directives inside it to communicate with 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);
  }
}

Check out the complete implementation on StackBlitz.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to utilize Bootstrap 5 flex for aligning text in the center position

Within these specific divs: <div class="col-6 col-md-4 col-lg-3 col-xl-2 my-3"> <a href="#" title="Falazóhabarcs" class="main_category d-flex justify-content-between align-items-center radius p-3&quo ...

Error in Angular: The type 'Response' is not generic

Currently, I am attempting to extract a nested array from an HTTP response with Angular 14 getItems(): Observable<Item[]> { return this._httpClient.get<Item[]>(this.apiUrl + 'items').pipe( tap((items) => { t ...

Issues with Angular 9 routerLinkActive functionality causing unexpected behavior

Whenever I navigate to a different router link, the previous link remains active, resulting in multiple active links with the same class. <div class="side-link" [routerLink]="['/']" [routerLinkActive] = "['link-active']">Dashboar ...

Error encountered when running Angular 11 with SSR using @nguniversal/express-engine: "ReferenceError: globalThis is not defined"

Encountering issues while attempting to integrate @angular/fire with Angular 11 and @nguniversal/express-engine for server-side rendering (SSR). Upon initializing AngularFireModule in app.module.ts, errors arise when running the commands npm run dev:ssr or ...

The hidden pop-up window from a particular tool is currently not being displayed

I attempted to upload my code onto Stackblitz in search of assistance with my dynamic modal not displaying. I am working on a function that I intend to be able to call from any component to create a popup where I can dynamically modify the header, body, an ...

Tips for enabling both vertical and horizontal scrolling using the mousewheel on a webpage

Our website features a unique scrolling functionality where it starts off vertically and then switches to horizontal once the user reaches the bottom. This allows for a seamless transition between scrolling directions. In addition, users can easily naviga ...

NativeScript encountered an error while trying to locate the module 'ui/sidedrawer' for the specified element 'Sidedrawer'

Currently, I am in the process of developing a simple side-drawer menu for my NativeScript application by following this helpful tutorial. I have successfully implemented it on a single page using the given code below. starting_point.xml: <Page xmlns ...

Encountering an error message stating "The variable 'App' is declared but not used" when running the index.tsx function

This React project is my attempt to learn how to use a modal window. The tutorial I've been following on YouTube uses JavaScript instead of TypeScript for their React project. However, I'm facing some challenges. Could you possibly help me ident ...

It seems that Ionic 2 does not support the registration of custom HTML tags

Encountering a problem with Ionic 2 and custom components. Developed a component to show in a list, serving as the list item. However, my app crashes when attempting to use the custom HTML tag. The stack trace is provided below. Uncertain about the issue. ...

The options passed to createReadStream in TypeScript do not accept {start: 90, end: 99}

After updating to TypeScript 1.6.2, I encountered an issue with my call to createReadStream(). The problem arises because the type definition in node.d.ts does not recognize 'start' and 'end' in the options parameter. var st = fs.crea ...

How to define an index signature in Typescript that includes both mandatory and optional keys

I am on a quest to discover a more refined approach for creating a type that permits certain keys of its index signature to be optional. Perhaps this is a scenario where generics would shine, but I have yet to unlock the solution. At present, my construc ...

jQuery Refuses to Perform Animation

I'm facing an issue with animating a specific element using jQuery while scrolling down the page. My goal is to change the background color of the element from transparent to black, but so far, my attempts have been unsuccessful. Can someone please pr ...

"An error occurred in Angular due to the absence of a defined user

Creating a variable boolean isEdit in Angular8 to differentiate between add and edit functionalities. Hello, I am looking to edit in angular8 by setting up a boolean variable isEdit for distinguishing between adding and editing. Greetings! Currently work ...

Change the CSS element if the current URL is not example.com/page1 or example.com/page2

When I apply the following JS code snippets, my output is incorrect or does not display at all. Below are the codes in question: if (location.href != "website.com/page1" || "website.com/page2") { element.style.backgroundColor='none'; ...

Unable to display SVG icon in Highcharts rendering

Is there a way to add a specific symbol in SVG format to a graph using Highcharts? Highcharts.SVGRenderer.prototype.symbols.download = function (x, y, w, h) { var path = [ "M19 5v14H5V5h14m1.1-2H3.9c-.5 0-.9.4-.9.9v16.2c0 .4.4.9.9.9h16.2c.4 0 ...

Seeking out a particular key within a JSON object and then finding a match based on the id within that key's array - how can it be

Recently, I've been exploring JavaScript and encountering challenges when trying to apply array methods on objects. For instance, I received a fetch response and my goal is to extract the 'entries' key and then utilize the native Array.find( ...

Adding a condition to the react-router v6 element: A step-by-step guide

I am currently in the process of updating my project from v5 to v6 of react-router-dom. However, I have encountered an issue. Everything was working fine in v5 <Route path={`${url}/phases/:phaseIndex`}> {(chosenPhase?.type === PhaseTy ...

Scroll the div back to the top when the form is submitted

I have set up a form in a pop-up using Bootstrap modal. The form is quite long, so after submission, the message appears at the top of the form. However, I want it to scroll to the top when the user submits the form so they can easily see the message. Is ...

Ways to align one child to the end without affecting any other elements

I'm attempting to position only div3 at the flex-end of .app. If I use this code: .app { display: flex; flex-direction: column; height: 100vh; justify-content: flex-end; } Div3 goes where I want it, but everything else also moves dow ...

django is not able to load staticfiles from the statifiles_dirs directory

I have placed my style.css in the directory appname/static/appname/. In my settings.py, this is what I have: STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static/"), ) When I try to load it in my base.html like t ...