2
votes

In angular material, we can pass colors to angular material components as attribute, for example

<button mat-raised-button color="primary">Example</button>

I'm using multiple angular material themes, which changes dynamically.

Required Behaviour: Changing color of my custom components dynamically with theme change.

I want something like this:

<app-footer color="primary"></app-footer>

How to get color in my custom component?


What I tried
I had a input property in my component

@Input() color;

and tried to pass color in component

<app-footer color="primary"></app-footer>

But it didn't worked for me.

How to achieve this?


==UPDATE==

Explanation: Below lines of code are from button.ts file of angular material from its github repository

/**
 * Material design button.
 */
@Component({
  moduleId: module.id,
  selector: `button[mat-button], button[mat-raised-button], button[mat-icon-button],
             button[mat-fab], button[mat-mini-fab], button[mat-stroked-button],
             button[mat-flat-button]`,
  exportAs: 'matButton',
  host: {
    '[attr.disabled]': 'disabled || null',
    '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
  },
  templateUrl: 'button.html',
  styleUrls: ['button.css'],
  inputs: ['disabled', 'disableRipple', 'color'],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})

Link to file: Button.ts

Here you can see, it takes color as input. Similarly, I have also taken color as input in my footer component. Now with <app-footer color="primary"></app-footer> I got primary string as input in my footer component.
How to get color hex from this to set background color of my footer component. Please note, primary color changes dynamically with theme change, therefore, I cannot hard-code color.

3
In what way didn't it work? Did you get an error in the console? - ShamPooSham
@ShamPooSham updated I got "primary" as string in component. I want to get color code from it. How to get that? - Harinder Singh
I think, angular material team did it in _button_theme.scss file. But still, I'm unable to achieve it in my footer component. Could you please explain me what they did in this file? (I'm new to scss) - Harinder Singh
If you write <app-footer [color]="color"></app-footer> (notice the [ brackets ]), it will evaluate the expression instead of just using the string you give to it. - ShamPooSham
@ShamPooSham Thanks for your help. I have found its solution which I have posted below. Please check. - Harinder Singh

3 Answers

3
votes

I found its solution. I'm posting it here so that if someone else requires similar behavior in their angular app, they can get it, in the following way.

I created a mixin for footer

 @mixin footer-theme($theme) {
        $primary: map-get($theme, primary);
        $accent: map-get($theme, accent);
        $warn: map-get($theme, warn);
        $background: map-get($theme, background);
        $foreground: map-get($theme, foreground);

        app-footer {
          .footer-primary {
              background-color: mat-color($primary);
          }
         .footer-accent {
              background-color: mat-color($accent);
          }
        }
      }

app-footer is a component selector and .footer-* is a class of footer component to whom I want to apply the primary/accent background color.

In the footer component, color is an input. We need to pass color value while embedding the footer component in the following way.
For the primary background color:

<app-footer color="primary"></app-footer>

For the accent background color:

<app-footer color="accent"></app-footer>

In the footer HTML file:

<div [ngClass]="{'footer-primary': color === 'primary', 'footer-accent': color === 'accent'}">
      /*footer code here...*/
</div>

Then I included footer mixin in app_theme.scss file which has multiple themes

@import '~@angular/material/theming';
@import './app/shared/footer/footer-theme';

@include mat-core();


$primary1: mat-palette($mat-teal, 500);
$accent1:  mat-palette($mat-green, A200, A100, A400);

$warn1:    mat-palette($mat-red);

$theme1: mat-light-theme($primary1, $accent1, $warn1);

@include angular-material-theme($theme1);
@include footer-theme($theme1);

// SECOND THEME
$primary2: mat-palette($mat-indigo, 500);

$accent2:  mat-palette($mat-blue, A200, A100, A400);

$warn2:    mat-palette($mat-red);

$theme2: mat-light-theme($primary2, $accent2, $warn2);

.second-theme {
    @include angular-material-theme($theme2);
    @include footer-theme($theme2);
}

In app.component.html

<div [ngClass]="{'second-theme' : isSecondTheme}">
    <div class="mat-app-background">
        <router-outlet></router-outlet>
    </div>
</div>

Here isSecondTheme is a boolean, when true second theme is applied, otherwise default theme. Just change boolean at runtime.

You can modify it to have more than two themes.

2
votes

You need to actually set the [color] property on the Angular Material component.

E.g.

color: string = 'primary'

Html:

<button [color]="color">My Button</button>

I've created a minimal example for your here.

1
votes

A little bit late but maybe somebody else can use it. Here's how I did it. i needed the warn color so I could use it on one of my own elements.

Html:

 //This is a dummy element, invisible to the user.
 <mat-icon color="warn" [style.display]="'none'" #warnIconButton>home</mat-icon>

Ts:

 @ViewChild('warnIconButton') _warnIconButton: MatButton
 _warnColor:string = 'myFallbackColor'

 ngAfterViewInit() {
   const warnNativeElement = this._warnIconButton._elementRef?.nativeElement
   this._warnColor = getComputedStyle(warnNativeElement)?.color
 }