Reusing Components in Angular 2
Asked Answered
U

3

7

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>
Ultramicroscope answered 26/8, 2016 at 22:2 Comment(0)
I
9

You can achieve this by using @Input decorator. You can read more about it here. First, in your ButtonComponent, add a variable which will display button name, like this:

export class ButtonComponent {

    @Input() buttonName: string;

}

Note: You need to import Input decorator: import { Input } from '@angular/core';

Then, in html use two-way data binding (interpolation) to display button value:

<button md-raised-button type="button" class="btn text-uppercase flex-sm-middle">
    {{buttonName}}
</button>

And, finally, when you want to display button component, you can give button a name with a simple attribute value:

<custom-button buttonName="First Button"></custom-button>
<custom-button buttonName="Second Button"></custom-button>
<custom-button buttonName="Third Button"></custom-button>

I tried to keep this as simple as possible, feel free to ask questions if you encounter any problems.

Incoordination answered 26/8, 2016 at 22:51 Comment(1)
Thank you for keeping it very simple. Can you please consider a stackblitz example ?Warfare
C
17

"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.

Clepsydra answered 26/8, 2016 at 23:2 Comment(1)
Thanks!! Definitely covered all my questions with clear working answers.Ultramicroscope
I
9

You can achieve this by using @Input decorator. You can read more about it here. First, in your ButtonComponent, add a variable which will display button name, like this:

export class ButtonComponent {

    @Input() buttonName: string;

}

Note: You need to import Input decorator: import { Input } from '@angular/core';

Then, in html use two-way data binding (interpolation) to display button value:

<button md-raised-button type="button" class="btn text-uppercase flex-sm-middle">
    {{buttonName}}
</button>

And, finally, when you want to display button component, you can give button a name with a simple attribute value:

<custom-button buttonName="First Button"></custom-button>
<custom-button buttonName="Second Button"></custom-button>
<custom-button buttonName="Third Button"></custom-button>

I tried to keep this as simple as possible, feel free to ask questions if you encounter any problems.

Incoordination answered 26/8, 2016 at 22:51 Comment(1)
Thank you for keeping it very simple. Can you please consider a stackblitz example ?Warfare
H
2

You really should not bother writing specific CSS that depends on the ID of your component, this is not necessary.

Each component is encapsulated (by default). The encapsulation uses the Shadow DOM, or an emulation (default). For each component, you can choose one of the 3 encapsulation modes:

  • ViewEncapsulation.None -- no style encapsulation
  • ViewEncapsulation.Emulated -- the default, uses attributes to "encapsulate" the style
  • ViewEncapsulation.Native -- Uses Shadow DOM

Here is a good blog post about this topic: http://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html

Hinge answered 26/8, 2016 at 22:48 Comment(2)
Thanks. Does this encapsulation mean that if you do <h1 id="heading">abc</h1> somewhere inside the component html template, that the scope of that id is to the component only, so you can give elements in different components the same id?Ultramicroscope
Suppose you are in the default/emulated case, and your component's style is encapsulated with an attribute: [_ngcontent-1] Now, any of your component CSS rule will be provided automatically with a [_ngcontent-1] at the top root of the selector. The easiest way to understand is to inspect the styles of an Angular 2 component at run-time with the developer tools. I think you should really keep your IDs unique in the application, you don't need them inside a component.Hinge

© 2022 - 2024 — McMap. All rights reserved.