17

I am trying to create a component in Angular 5 that will house a reusable template for a button. In different parts of my app buttons will call different functions, so I would like to be able to tell the given instance of the button what function to call. I know I could create an HTML tag for a button wherever I need it, but I was hoping I could create a reusable component so I can ensure formatting is consistent throughout the app.

Error

 Got interpolation ({{}}) where expression was expected at column 0 in 
        [{{functioncall}}]

Component

<div id = "button">
  <button type="button" class= "btn" (click) ="{{functioncall}}" >{{label}}</button>
</div>

And HTML

 import { Component, OnInit, Input } from '@angular/core';

    @Component({
      selector: 'app-button',
      templateUrl: './button.component.html',
      styleUrls: ['./button.component.css']
    })
    export class ButtonComponent implements OnInit {
      @Input() label:string;
      @Input() functionCall:string;

      constructor() { }

      ngOnInit() {
      }
    }

4 Answers 4

24

you have to use the @Output decorator to emit some event (from child to parent)

button.component.ts:

@Input() label: string;
@Output() onClick = new EventEmitter<any>();

onClickButton(event) {
    this.onClick.emit(event);
  }

button.component.html:

<div id = "button">
  <button type="button" class= "btn" (click)="onClickbutton($event)" >{{label}}</button>
</div>

parent.component.ts

label = "button label"

  functioncall(event) {
    console.log('functioncall', event);
  }

parent.component.html

<app-button (onClick)="functioncall($event)" [label]="label"></app-button>

See example: https://stackblitz.com/edit/angular-gghsax

Sign up to request clarification or add additional context in comments.

4 Comments

I refreshed the app with a new StackBlitz link as your link doesn't work anymore (stackblitz.com/edit/angular-gghsax). Furthermore I think you were missing @Input() label: string; as a variable declaration in button.component.ts (at least that error was thrown) - might be a compatiblity issue (Angular 7 now). However, awesome work!
lets say i want a icon in the button (google icons like shopping cart). How do i add that dynamically?
You can use angular Content Projection to do that. see this example stackblitz.com/edit/…
Hard coded IDs like id = "button" should be avoid in a component. Components are meant to be reusable and IDs must be unique. Otherwise markup conformity is compromised. One more point: I don't think wrapping each button in a div is a straight forward.
11

In addition to @miladfm answer, I'd recommend using the <ng-content></ng-content> directive here to pass content through instead of pulling in {{label}}, assigning the @Output decorator to click instead of onClick, and using the MouseEvent type instead of any. Using these changes will allow the button component to behave syntactically more like a native button when it's consumed:

button.component.ts

...
@Output() click = new EventEmitter<MouseEvent>();

onClickButton(event) {
  this.onClick.emit(event);
}
...

button.component.html

<div id = "button">
  <button type="button" class="btn" (click)="onClickbutton($event)">
    <ng-content></ng-content>
  </button>
</div>

parent.component.ts

...
functioncall(e: MouseEvent) {
 // do stuff
}
...

parent.component.html

<app-button  (click)="functioncall($event)">Your Label Here</app-button>

2 Comments

Seems like having the event named click will trigger the click event twice, so I would stick to the onClick name.
Or, you can use event.stopPropagation() like described here: stackoverflow.com/a/42112272/612847
1

Reusable Component - it's work for me

I have created button as reusable component

  • button.component.html

    < button type="button" class= "btn" >{{label}} < / button >

  • button.component.ts

    export class ButtonComponent {
    
          @Input() label: string;
    
          @Output() onClick = new EventEmitter<any>();
    
          constructor() {}
    
          onClickButton(event) {
    
              this.onClick.emit(event);
    
          }
     }
    
  • user.component.html

    < app-button (click)="functioncall($event)" [label]="label"> < /app-button >

  • user.component.ts

    label = 'Hello World';

Comments

0

This implementation allows for direct access to the host events using @HostListener without the need to add additional HTML elements such as divs or buttons within your template just to be able to access these events.

Here's an example of its usage

app.component.html

<app-button (app-mousedown)="navigateHome()">Click Me!</app-button>

button.component.ts

import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';

@Component({
  selector: 'app-button',
  standalone: true,
  imports: [LoadingSpinnerComponent],
  templateUrl: './button.component.html',
  styleUrl: './button.component.scss',
})
export class ButtonComponent {
  @Input() loading = false;
  @Output('app-mousedown') event = new EventEmitter<MouseEvent>();

  @HostListener('mousedown', ['$event'])
  handleMousedown(event: MouseEvent) {
    this.event.emit(event);
  }
}

button.component.html

@if (loading) {
  <app-loading-spinner [width]="17" [height]="17" [borderWidth]="2" />
} @else {
  <ng-content> </ng-content>
}

button.component.scss

@import "../../styles.scss";

:host {
  position: relative;
  display: flex;
  padding: 10px 30px;
  justify-content: center;
  align-items: center;
  width: fit-content;
  border-radius: 10px;
  font-size: 15px;
  min-width: 100px;
  min-height: 40px;
  outline: none;
  margin-right: 7px;
  overflow: hidden;
  transition: background-color 0.1s ease;
  background-color: white;
  outline: 1px solid $color;
  cursor: pointer;
  &:hover {
    background-color: rgb(239, 243, 246, 0.8);
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.