Home > Mobile >  Angular Material: MatRadioButton not working when getting data from a provider
Angular Material: MatRadioButton not working when getting data from a provider

Time:12-05

I want to implement a theme selector for my Angular app which uses the Material design but I just can't get the radio buttons to work.

I encapsulated everything related to theming in an own service, including a function getThemes() returning an array of theme names. The service is injected correctly and everything renders correctly but I am not able to change the values of the radios. Here are both approaches side by side:

<mat-radio-group>
  <!--  getThemes() inside my provider returns a hardcoded array, no async stuff -->
  <!--  Things render correctly but buttons are not clickable -->
  <mat-radio-button *ngFor="let theme of themeSelector.getThemes()" [value]="theme.name">
    {{theme.name}}
  </mat-radio-button>
</mat-radio-group>


<mat-radio-group>
  <!--  Exactly the same as before but now with hardcoded array inside my component -->
  <!--  Everything works as expected -->
  <mat-radio-button *ngFor="let theme of themes" [value]="theme.name">
    {{theme.name}}
  </mat-radio-button>
</mat-radio-group>

Maybe the app does not wait properly for the service to finish but as there is no asynchronicity I expected things to be less complicated.

DevTools reveal that the [value] attributes are set correctly after the page has loaded.

Any help would be really appreciated but if that would make things really complicated, I would rather go with defining the themes directly within the component (although this is probably not the best way).

EDIT: As requested, the getThemes() function:

getThemes = (): Theme[] => {
    return [
      {
        name: 'deeppurple-amber'
      },
      {
        name: 'indigo-pink'
      },
      {
        name: 'pink-bluegrey'
      },
      {
        name: 'purple-green'
      }
    ];
  };

, where Theme is a type consisting only of a name.

CodePudding user response:

It's better not to use functions in Angular directives because that functions may be called several times instead of one time ( without value change ), you can do something like

this.themes = this.themeSelector.getThemes()

in ngOnInit to avoid that.

If that didn't work the issue might be because themeSelector.getThemes() is returning empty array instead of null in that case you can change returned data or surround *ngfor with

*ngif(data && data.length > 0)

CodePudding user response:

Use getTheme() as a getter instead of a function inside your service, which is more ideal for your use case, and then call it anywhere just like a variable (without ()).

like this -

myThemes = [
    {
      name: 'deeppurple-amber',
    },
    {
      name: 'indigo-pink',
    },
    {
      name: 'pink-bluegrey',
    },
    {
      name: 'purple-green',
    },
  ];

  get themes() {
    return this.myThemes;
  }

see the working example here

CodePudding user response:

While the suggested answers both work properly, I found out the actual reason why my first approach was failing.

I instantiated a new array each time the method getThemes was called and thus each array was a new object, most probably messing up the data binding.

  • Related