angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

Add spinner to mat-button #15982

Closed jpike88 closed 3 years ago

jpike88 commented 5 years ago

Please describe the feature you would like to request.

mat-button clicks often involve an asynchronous operation. Adding a progress spinner or some sort of 'waiting' function makes sense. Disabling the button isn't good enough as it can appear broken to a user.

What is the use-case or motivation for this proposal?

Sometimes async operations can involve a few seconds or more as the server is doing something. Users need a visual cue that they should be waiting.

andreElrico commented 5 years ago

Cant you add a spinner into the button and disable clicking the button via css?

andrewseguin commented 5 years ago

I don't suspect this will be on the roadmap for a while, but in the meantime you should be able to set this up by overlaying the button with a spinner like @andreElrico suggested

Here's an example of this: https://stackblitz.com/edit/angular-k5a64z?file=app/button-overview-example.ts

simeyla commented 5 years ago

Shame this won't be done for a while - especially since it's part of the material spec.

This project does it very nicely, but 'native' support would be great.

https://github.com/michaeldoye/mat-progress-buttons Demo: https://mat-progress-buttons.firebaseapp.com/home

For simple 'Save' functionality these are a very nice touch.

meowso commented 4 years ago

Shame this won't be done for a while - especially since it's part of the material spec.

This project does it very nicely, but 'native' support would be great.

https://github.com/michaeldoye/mat-progress-buttons Demo: https://mat-progress-buttons.firebaseapp.com/home

For simple 'Save' functionality these are a very nice touch.

It does not support static i18n tags, and it has a lot of open issues still.

This MUST be supported natively, as a state of a button.

andreElrico commented 4 years ago

@simeyla why should the Material team waste time when you can simply combine the two components yourself? There is so much important stuff to do.

The fact its mentioned in the specs does not mean it needs to be implemented by the mat-team. Its a guide how things should look and feel. Everything the mat-team builds should meet the specs requirements.

simeyla commented 4 years ago

@AndreEllrich I'm not insisting on anything. I just said it was a shame. But in answer to your question

As I said a spinner button is a very useful control to have and wouldn't take a huge amount of time for an expert to create.

Anyway here's the version I ended up with - if it helps anyone then great :-)

  <rr-spinner-button [isBusy]="isSaving" buttonStyle="flat" 
                     (click)="saveChanges()">Save</rr-spinner-button>
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';

@Component({
    selector: 'rr-spinner-button',

    template: `<button mat-button 

                    [color]="color"
                    
                    [class.mat-flat-button]="buttonStyle == 'flat'"
                    [class.mat-raised-button]="buttonStyle == 'raised'"
                    [class.mat-stroked-button]="buttonStyle == 'stroked'"

                    [class.busy]="isBusy"
                    [disabled]="isDisabled"
                    [type]="type">

                    <div class="content" [class.busy]="isBusy">
                        <ng-content></ng-content>
                    </div>

                    <mat-spinner [mode]="'indeterminate'" 
                                 [diameter]="19" 
                                 [class.busy]="isBusy"></mat-spinner>
               </button>

               `,

    styles: [`  :host 
                {
                    position: relative;
                }

                :host.disabled
                {
                    // outline: 1px solid red;
                    pointer-events: none;
                }

                mat-spinner 
                { 
                    position: absolute;
                    top: 25%;

                    opacity: 0;

                    transition: opacity .3s ease-in-out;
                }

                mat-spinner.busy 
                {
                    opacity: 1;
                }

                .content 
                {
                    opacity: 1;
                    transition: opacity .3s ease-in-out;
                }

                .content.busy 
                {
                    opacity: 0;
                }

                button ::ng-deep .mat-button-wrapper
                {
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
             `
            ],

    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SpinnerButtonComponent {

    // inspired by https://www.npmjs.com/package/mat-progress-buttons
    constructor() { }

    @Input("isBusy")
    isBusy = false;

    @Input("disabled")
    disabled = false;

    @Input("color")
    color!: string;

    @Input("type")
    type: 'button' | 'submit' = 'button';

    @Input('buttonStyle')
    buttonStyle: 'flat' | 'raised' | 'stroked' = 'flat';

    @HostBinding('class.disabled')
    get isDisabled() 
    {
        return this.isBusy || this.disabled;
    }
}
meowso commented 4 years ago

Andre,

This is not wasting time, angular components is a bootstrap for applications, and by the 2k downloads weekly that the rogue implementation has you can see there is demand for it.

They also covered this scenario in the material specs because it is a very common use for async activities.

Combining both components is not enough, there is state management, transition, animation. It's alot of hardwork for something that should come out of the box.

Yours,

via Newton Mail [https://cloudmagic.com/k/d/mailapp?ct=pa&cv=10.0.25&pv=9&source=email_footer_2] On Fri, Jan 17, 2020 at 6:45am, AndreEllrich < notifications@github.com [notifications@github.com] > wrote: @simeyla [https://github.com/simeyla] why should the Material team waste time when you can simply combine the two components yourself? There is so much important stuff to do.

The fact its mentioned in the specs does not mean it needs to be implemented by the mat-team. Its a guide how things should look and feel. Everything the mat-team builds should meet the specs requirements.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub [https://github.com/angular/components/issues/15982?email_source=notifications&email_token=AAU4DNIOH7DQ35BAQ2YPSRTQ6FAYVA5CNFSM4HLYO72KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJGQWSI#issuecomment-575474505] , or unsubscribe [https://github.com/notifications/unsubscribe-auth/AAU4DNNVIGATLQL327IJCITQ6FAYVANCNFSM4HLYO72A] .

andreElrico commented 4 years ago

Hey Simeyla,

nice try: However you are reinventing the wheels here! (which means reimplemting the mat-button api.) I used a compound component style:

https://stackblitz.com/edit/angular-k5a64z-bfbkuw?file=app%2Fbutton-overview-example.html

<app-mat-spinner-btn [loading]="loading">
  <button mat-raised-button (click)="'Something'">Click me!</button>  
</app-mat-spinner-btn>

please note:


Angular 8.2.9, with some mild css animation

https://stackblitz.com/edit/angular-9vfbuy?file=src%2Fstyles.scss

simeyla commented 4 years ago

You proved my point which is that the one in the spec looks better than both of our attempts :)

I did not want a spinner that just faded out the button to grey. I needed the button contents to disappear so that’s why I choose the way I did it. Fastest way I could because yes better things to do!

Anyway still hoping one day they’ll add it and save everyone some time.

On Fri, Jan 17, 2020 at 02:14 AndreEllrich notifications@github.com wrote:

Hey Simeyla,

nice try: However you are reinventing the wheels here! (which means reimplemting the mat-button api.) I used a compound component style:

https://stackblitz.com/edit/angular-k5a64z-bfbkuw?file=app%2Fbutton-overview-example.html

<app-mat-spinner-btn [loading]="loading"> <button mat-raised-button (click)="'Something'">Click me!

please note:

  • this is angular7 in 8+ you will have to tweak a few things. I think the material import need to be from material/button i believe
  • css can be improved, see if you can avoid important ... but I thinks its okay here!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/angular/components/issues/15982?email_source=notifications&email_token=AA34UVTZFZ6Y5V3VEETL4RDQ6GAJNA5CNFSM4HLYO72KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJHGLLY#issuecomment-575563183, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA34UVXFQQRODDC5BFFTEL3Q6GAJNANCNFSM4HLYO72A .

andreElrico commented 4 years ago

This can be done very easily with css. If i have time ill update. To be honest I did not look at the specs :D

DavidAlfonsoo commented 4 years ago

Hi, I found a simple trick

      <button *ngIf="!this.SpinerC2" class="space-boton" mat-raised-button color="warn">
        Update Tickets<mat-icon><mat-progress-spinner diameter="20" mode="indeterminate" strokeWidth="11%"> 
        </mat-progress-spinner></mat-icon>
      </button>

Put your mat-progress-spiner in a mat-icon tag. it works for me!

jmagaram commented 3 years ago

Agree this would be a super-useful addition. I'm having trouble figuring out how to implement something like this. Must be a very common scenario. @DavidAlfonsoo suggestion works but don't want to hardcode a diameter. A couple other solutions here involve hardwiring the spinner diameter which is not a good idea. I may end up using the bar progress instead simply because I can dock it to the top of the panel.

jelbourn commented 3 years ago

Duplicate of #13667

angular-automatic-lock-bot[bot] commented 3 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.