Reusing Components in Angular 2

BeniaminoBaggins picture BeniaminoBaggins · Aug 27, 2016 · Viewed 14.9k times · Source

When I started using Angular 2 I had the idea that the main reason to create components is because you can reuse them. EG:

<custom-button id="button1">button 1</custom-button>
<custom-button id="button2">button 2</custom-button>

Is it the case that this is a large reason to go with angular 2 and components in a web app, and it can be done?

I haven't found a resource that specifically answers my question about how to do this.

I'd like to create a button, and an input, the 2 most basic and commonly used html elements, and make them reusable.

I tried to make a button component and reuse it.

I tried to use it in an html template like this:

<custom-button>some text</custom-button>
<custom-button>different text</custom-button>

However the text did not show up on the button. Can this be done?

Another thing I'm wondering about is unique html id's when doing this. Am I able to add a unique html id attribute to each instance?

Maybe like:

<custom-button id="display-bikes">bikes</custom-button>
<custom-button id="display-helmets">helmets</custom-button>

And then I can do some specific css using the unique id of the element?

That's all I want to know, and how to do it.

However here is the rest of my code involved:

component:

import { Component } from '@angular/core';
@Component({
    selector: 'custom-button',
    templateUrl: 'app/shared/button.component.html',
    styleUrls: ['app/shared/button.component.css']
})
export class ButtonComponent { }

css:

button {
  font: 200 14px 'Helvetica Neue' , Helvetica , Arial , sans-serif;
  border-radius: 6px;
  height: 60px;
  width: 280px;
  text-decoration: none;
  background-color: $accent;
  padding: 12px;
  color: #FFF;
  cursor: pointer;
}

button:focus {
    outline:0 !important;
}

html:

<button md-raised-button type="button" class="btn text-uppercase flex-sm-middle">
try now <!-----lets get rid of this and let the client decide what text to display somehow???
</button>

Answer

ABabin picture ABabin · Aug 27, 2016

"Can this be done?"

Yes! It's called transclusion or content projection and you can read about it in detail here.

Here's how:

In button.component.html:

<button>
    <ng-content></ng-content>
</button>

Then, whenever you put content inside of the tags for the component, like this: <custom-button id="display-bikes">bikes</custom-button>, the Angular 2 compiler will 'project' it into the component's template inbetween the ng-content tags. So ultimately, you'd get this at runtime:

<button>
    bikes
</button>

That's just a simple example. You can get really advanced with it and do things like project other components and have multiple <ng-content> outlets. Read about that at the blog linked above.

And then I can do some specific css using the unique id of the element?

Also, yes... though you wouldn't use the standard id attribute.

On your ButtonComponent:

import { Component, Input } from '@angular/core';
@Component({
  selector: 'custom-button',
  templateUrl: 'app/shared/button.component.html',
  styleUrls: ['app/shared/button.component.css']
})
export class ButtonComponent {
  @Input() styleId: string;

  //...
}

Say that button.component.css has two classes named class-one and class-two.

In button.component.html:

<button [ngClass]="{class-one: styleId === 'applyClassOne', class-two: styleId === 'applyClasstwo'}">
    <ng-content></ng-content>
</button>

Then you bind to the Input property in the parent like so:

<custom-button [styleId]="'applyClassOne'"></custom-button>
<custom-button [styleId]="'applyClassTwo'"></custom-button>

There are other ways of applying styles dynamically, but this one is the simpliest given that there are only two classes to choose from.