Open mfarhani opened 5 years ago
you could just use the render 2 library remove/set attribute library for this
edit: cant actually do this, just use
<button *ngIf="!stroked" mat-button>Text</button>
<button *ngIf="stroked" mat-button-stroked>Text</button>"
you could just use the render 2 library remove/set attribute library for this
If i using setAttribute for this purpose, what should place instead value?
renderer.setAttribute(elRef,'mat-stroked-button','value')
it seems this cant actually be done using setAttribute since mat-button seems to be a directive
why not just use ngIf, this is usually the most common way to address something like this
<button *ngIf="!stroked" mat-button>Text</button>
<button *ngIf="stroked" mat-button-stroked>Text</button>"
I've had a similar question at stackoverflow, but nobody had a better idea... I understand why it can't be done, but it's sad I have to make 2 buttons all the time.
I'm using a CMS to allow adding buttons dynamically and for the button.type I'm doing something like this:
export interface Button {
id: string;
text: string;
type: string;
color: string;
routerLink: string;
}
<ng-container [ngSwitch]="data.type">
<a *ngSwitchDefault mat-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'raised'" mat-raised-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'stroked'" mat-stroked-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'flat'" mat-flat-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'icon'" mat-icon-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'fab'" mat-fab [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
<a *ngSwitchCase="'mini-fab'" mat-mini-fab [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a>
</ng-container>
Thanks @intellix , i wrote some code similar this.
<button mat-button [ngClass]="condition ? 'mat-raised-button' : 'mat-stroked-button'">Button</button>
You can also use 'mat-flat-button' instead of 'mat-raised-button' if you don't need extra styling such as shadow.
Dynamically setting the class works currently just because, based on the button source code (https://github.com/angular/components/blob/master/src/material/button/button.ts#L105) it's pretty much everything that those different attributes (mat-raised-button, mat-stroke-button, etc) do. However, it's not a part of the official mat button api - so this can break in future.
I'm wondering if it would make sense to introduce a new input for a button variant (similar to variant
prop in React's Material implementation: https://material-ui.com/components/buttons/) and deprecate existing attributes over time? For instance, we already have a single color
input instead of relying on multiple mat-color-primary
/ mat-color-accent
attributes.
<button mat-button [ngClass]="condition ? 'mat-raised-button' : 'mat-stroked-button'">Button</button>
You can also use 'mat-flat-button' instead of 'mat-raised-button' if you don't need extra styling such as shadow.
amazing, just what I was looking for. thank you!
The idea of doing this is nice:
<button mat-button class="mat-raised-button" color="primary">
But it doesn't really work due to .mat-button having more precedence on color and causing various other issues, which comes from theming.scss within Material:
.mat-button.mat-primary {
color: black;
}
.mat-raised-button {
color: white;
}
So I guess I have to go back to my solution which is even more problematic as I need to dynamically support <a>
or <button>
so have to duplicate all of that again.
My dynamic buttons/anchors from CMS were at 36 LOC but since I can't do that, I'm back to 200 LOC to achieve it since I need to switch over the variants for both anchors and buttons
Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.
Find more details about Angular's feature request process in our documentation.
Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.
We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.
You can find more details about the feature request process in our documentation.
It's the year 2022. Libraries roam the land, and TypeScript reigns supreme. A lone developer drags his weary companion, the "Reusable Component" onto a rock to rest. He asks, "What's wrong, why are you so exhausted?" Reusable Component replies, "My body grows tired from copy pasting lines of code..." The developer responds, "Why don't you just change one attribute dynamically instead of rewriting 8 lines for eternity?" Reusable Component grasps the developers face and looks him straight in the eye and whispers, "I can't." Overcome with exhaustion, he expires there, becoming one with the landscape, never to be noticed or cared about again...
I've spent the last while looking for a way to dynamically set directives, and it seems quite counter-productive to require developers to rewrite the same element over and over. My use case is for a simple reusable button component that fits our design system. It's essentially an abstraction from Material so developers and designers never have to worry about if things change. However, to capture the 7 different button states, I'm being told that I need to write 7 duplicate lines of code with "if" statements to toggle between the two? Is there any way around this particular flavor of madness?
This is the simplest solution i could find, based on v14 button directive and HTML.
I can work on a PR but I don't know if mat-dynamic-button
is ok as selector name.
https://stackblitz.com/edit/angular-vf9m7n
Since this component is using styles from button component and if you don't have any material button directive on any loaded component, button styles are unloaded. You can prevent it by adding a simple hidden mat-button
to your root component or your layout view if you are using routing.
DynamicButtonType can be simplified as basic, raised, stroked and flat but you need to map them to class names.
Spot on, @AStoker. Designers shouldn't care about what type of button developers use. Developers shouldn't care about what a button should look like. Madness indeed.
I'm using a CMS to allow adding buttons dynamically and for the button.type I'm doing something like this:
export interface Button { id: string; text: string; type: string; color: string; routerLink: string; }
<ng-container [ngSwitch]="data.type"> <a *ngSwitchDefault mat-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'raised'" mat-raised-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'stroked'" mat-stroked-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'flat'" mat-flat-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'icon'" mat-icon-button [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'fab'" mat-fab [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> <a *ngSwitchCase="'mini-fab'" mat-mini-fab [color]="data.color" [routerLink]="data.routerLink">{{ data.text }}</a> </ng-container>
Thank you
Hi there,
I think it would be really helpful if the HOST_SELECTOR_MDC_CLASS_PAIR
variable could be exported in the API. This would allow developers to have more control over setting button type classes dynamically. Alternatively, it would be great to have the class decision moved to a later point in the code or even to a method that can be called manually.
It's the year 2022... Is there any way around this particular flavor of madness?
The year is 2023, madness persists. Is there a better solution for this besides an ng-switch
or ng-if
yet?
It should be possible with this example.
<button
[mat-button]="isMaterialButton"
[ngClass]="{ 'mat-button-stroked': isMaterialButton && isStroked }"
[color]="isMaterialButton && isPrimary ? 'primary' : ''"
>
Click me
</button>
@Fanalea , that would only change the class. The issue here isn't exactly about setting the class dynamically, but rather setting the type, or an attribute dynamically.
In my case, I found out that, if you have a mat-icon inside of the button, setting the class with ngClass makes the icon to lose its alignment. I fixed it by manually adding a <span class="mat-button-wrapper">
, I don't know why but it was missing. Hope this helps someone.
Hello, I came across the same problem and ended up finding this solution which I found more useful, since the remaining behavior is centralized, just with the variation of the button type.
Font: https://stackoverflow.com/a/75980043/16881969 Angular Material >= 15.
your-cmponent.ts
@Input() label = '';
@Input() type: 'basic' | 'raised' | 'stroked' | 'flat' | 'icon' | 'fab' | 'mini-fab' = 'stroked';
@Input() color: 'basic' | 'primary' | 'accent' | 'warn' | 'disabled' | 'link' = 'basic';
your-cmponent.html
<button
mat-button
[color]="color"
[ngClass]="{
'mat-mdc-button mat-mdc-button': type === 'basic',
'mat-mdc-button mat-mdc-raised-button': type === 'raised',
'mdc-button--outlined mat-mdc-outlined-button': type === 'stroked',
'mat-mdc-unelevated-button': type === 'flat',
'mdc-icon-button mat-mdc-icon-button': type === 'icon',
'mdc-fab mat-mdc-fab': type === 'fab',
'mdc-fab mdc-fab--mini mat-mdc-mini-fab': type === 'mini-fab'
}">
{{ label }}
</button>
@willflame The only issue with that is if the class names change in the future your code may break.
You'll have to use a *ngIf
or *ngSwitch
wrapper around your buttons so that classes are added dynamically. The following should be future proof as long as the directives mat-button
and mat-raised-button
don't change.
<ng-container [ngSwitch]="type">
<button *ngSwitchCase="'basic'" mat-button></button>
<button *ngSwitchCase="'raised'" mat-raised-button></button>
...
</ng-container>
This is the best solution I've found so far.
@willflame Quick tip you can use ThemePalette
for your colors (or at lest the base colors). Then you don't need to redefine all the string literals:
@Input() color: import('@angular/material/core').ThemePalette = ...
It blows my mind that this is still a problem 4 years later. The ngClass work around no longer works in v17 with safari. Something as simple as going from mat-stroked-button to mat-flat-button when pressed shouldn't be this hard.
How hard is it to just provide a type for the button instead of having multiple directives which were never flexible.
Hi all, any updates on this yet? Just checking in
Cheers I also had this issue ... if you only want to modify the mat-button to stroked flat raised ... this works fine
`import { Directive, ElementRef, Input, Renderer2, inject } from '@angular/core'; import { BnButtonType } from '../../interfaces/src/bn-button-type'; import { BnRendererUtil } from '@binom/sdk-utils/renderer';
@Directive({ selector: 'button[bnMatbutType]', exportAs: "bnMatbutType", standalone: true, }) export class BnMatbutTypeDirective {
private renderEl: BnRendererUtil; private renderer = inject(Renderer2);
private el = inject(ElementRef);
@Input() set bnMatbutType(val:BnButtonType){ this.renderEl.removeClasses([ 'mat-mdc-button', 'mdc-button--unelevated', 'mat-mdc-unelevated-button', 'mdc-button--raised', 'mat-mdc-raised-button', 'mdc-button--outlined', 'mat-mdc-outlined-button']);
let classes=[]
switch(val){
case 'stroked':
classes = ['mdc-button--outlined', 'mat-mdc-outlined-button']; break;
case 'raised':
classes = ['mdc-button--raised', 'mat-mdc-raised-button']; break;
case 'flat':
classes = ['mdc-button--unelevated', 'mat-mdc-unelevated-button']; break;
case '': default:
classes = ['mat-mdc-button']; break;
}
this.renderEl.addClasses(classes)
}
constructor() { this.renderEl = new BnRendererUtil(this.renderer, this.el); }`
... <button mat-button color="accent" [bnMatbutType]="butType" ...
Please describe the feature you would like to request.
I'm using MatButton directive as attribute like this:
<button mat-button buttonType="{{button.type}}></button>"
I want to change 'mat-button' directive according to 'button.type', for example if 'button.type' is 'stroked' then 'mat-button' changed to 'mat-stroked-button'. How can to change type of button dynamicaly?What is the use-case or motivation for this proposal?
Is there anything else we should know?