Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generalising button component further

Tags:

angular

I have two components:

  <app-google-login-button></app-social-login-button>
  <app-facebook-login-button></app-facebook-login-button>

app-facebook-login-button looks like this:

<button type="button" class="btn btn-label btn-facebook" (click)="facebookSignIn()"
  *ngIf="!(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="['fab', 'facebook']" size="xs"></fa-icon>
  </label> Sign in with Facebook
</button>
<button type="button" class="btn btn-label btn-facebook" (click)="mobileFacebookSignIn()"
  *ngIf="(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="['fab', 'facebook']" size="xs"></fa-icon>
  </label> Sign in with Facebook
</button>

app-google-login-button looks like this:

<button type="button" class="btn btn-label btn-google" (click)="googleSignIn()" *ngIf="!(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="['fab', 'google']" size="xs"></fa-icon>
  </label> Sign in with Google
</button>
<button type="button" class="btn btn-label btn-google" (click)="mobileGoogleSignIn()" *ngIf="(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="['fab', 'google']" size="xs"></fa-icon>
  </label> Sign in with Google
</button>

I'd like to combine both and have a generic app-social-login-button. How would the component look like?

like image 286
methuselah Avatar asked Aug 17 '26 20:08

methuselah


2 Answers

Define an interface that declares the configurable options, but also include a callback function for when the button is clicked. If you don't want to inject a callback for every button, then an alternative is to define a string token like "facebook" and pass that value to a shared service.

export interface SocialButton {
    // button text
    title: string;

    // Font Awesome icon
    icon: any;

    // CSS class for the button
    btn: string;

    // make mobile just a condition of the click
    click: (mobile: boolean) => void;
}

You can then pass an object of the above interface as a parameter to the component.

@Component({
    selector: 'app-social-login-button',
    template: `
        <button type="button"
                [ngClass]="getClass()"
                (click)="click()">
            <label>
                <fa-icon [icon]="options.icon" size="xs"></fa-icon>
            </label> Sign in with {{options.title}}
        </button>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SocialLoginButtonComponent {

    @Input()
    public options: SocialButton;

    public isMobile: Observable<any>;

    public getClass() {
        return {
            'btn': true,
            'btn-label': true,
            [this.options.btn]: true
        };
    }

    public click() {
        this.isMobile
            .pipe(first())
            .subscribe(value => this.options.click(value));
    }
}

You can define a shared service that will create the SocialButton options as an array.

@Injectable()
export class SocialButtonService {
    public buttons(): SocialButton[] {
        return [this.faceBook(), this.google()];
    }

    public faceBook(): SocialButton {
        return {title: 'Facebook', icon: ['fab', 'facebook'], btn: 'btb-facebook', click: (m) => this.signIn('facebook', m)}
    }

    public google(): SocialButton {
        return {title: 'Google', icon: ['fab', 'google'], btn: 'btb-google', click: (m) => this.signIn('google', m)}
    }

    public signIn(platform: string, mobile: boolean) {
        // do work
    }
}

You can show all the buttons easily now in another component.

@Component({
    template: `
    <app-social-login-button *ngFor="let option of options" [options]="option"></app-social-login-button>
    `
})
export class SocialLoginButtonsComponent {
    public options: SocialButton[];

    public constructor(service: SocialButtonService) {
        this.options = service.buttons();
    }
}

From the HTML code provided, I can give you some suggestions.

  1. Create an ENUM which would have list of social media. (this would restrict the value of social media which can be passed to the component)

  2. Create a component for app-social-login-button with @Input params as Enum value (either Google or facebook).

  3. Inside component SocialLoginButtonComponent, check for the passed value and have the HTML something like:

<button type="button" class="btn btn-label btn-facebook" (click)="SignIn()"
  *ngIf="!(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="iconArray" size="xs"></fa-icon>
  </label> Sign in with {{companyName}}
</button>
<button type="button" class="btn btn-label btn-facebook" (click)="SignInWithMobile()"
  *ngIf="(isMobile | async)?.matches">
  <label>
    <fa-icon [icon]="iconArray" size="xs"></fa-icon>
  </label> Sign in with {{companyName}}
</button>

in the component, check for the @Input param and set companyName, iconArray .Configure SignIn() and SignInWithMobile() accordingly to call APIs of respective companies.

  1. You can also create a MediaService which will handle SignIn API calls depending on the Company Name. Try not to put all the logic in the component itself.
like image 27
Shashank Vivek Avatar answered Aug 20 '26 12:08

Shashank Vivek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!