DEV Community

Shivam
Shivam

Posted on

Angular's DI can make your components smarter

Image description

Angular's built in Dependency Injection is quite powerful and today we are going to see how we can use it to make our components smart(er).

Let's talk about button component

<app-button  
accent=" primary | danger | success | ... "
size =" small | medium | large | cta | ... "
icon = "[ ... ]"
iconSize = "sm | md | lg | ..."
label = "[ ... ]"
translate = " true | false "
ripple = " true | false "
tooltip = "true | false"
...
 >
</app-button>
Enter fullscreen mode Exit fullscreen mode

Here, we can see that the button component provides different configuration option so that we could use it to cover different use cases.

Providing all these input's all the time could get cumbersome which could also lead to inconsistencies.

In order to solve this problem, we first have to find out all the places in our application where button could be placed.

for example

Place Button Size Icon Size Show Tool Tip Icon Only ...
App Header Large lg false false
Card Header Medium md false false
Table Row sm sm true true

Once we have clear idea of how and where our button is going to be used then we can create Angular's Injection Token for all the inputs where the value could be deduced from the context.

 const BUTTON_SIZE_HINT_TOKEN = new InjectionToken<
    small | medium | large | cta | ... 
>('Button size hint token', {
    providedIn: 'root',
    factory: () => 'medium' // default value
});

 const BUTTON_ICON_HINT_TOKEN = new InjectionToken<
    lg | md | sm | hide | ... 
>('Button size hint token', {
    providedIn: 'root',
    factory: () => 'md' // default value
});

const BUTTON_TOOLTIP_HINT_TOKEN = new InjectionToken<
    boolean
>('Button size hint token', {
    providedIn: 'root',
    factory: () => false // default value
});

...
Enter fullscreen mode Exit fullscreen mode

After creating these tokens, we have to use it in the button component.

// button.component.ts
// ...
// ... code ommited for brevity


 constructor(
    @Inject(BUTTON_SIZE_HINT_TOKEN)
    private  buttonSize:   small | medium | large | cta | ... ,

    @Inject(BUTTON_ICON_HINT_TOKEN)
    private iconSize: lg | md | sm | hide | ...,

    @Inject(BUTTON_TOOLTIP_HINT_TOKEN)
    private showToolTip: boolean,

// ... other dependecies
    ){}
Enter fullscreen mode Exit fullscreen mode

Here, we can use these hints to the set the default value in the button component.

The next step would be to provide these hints in the places where the button is going to be used.

@Component({
    selector: 'app-page-header',
    templateUrl: './template-file.html',
    providers: [
        {
            provide: BUTTON_SIZE_HINT_TOKEN,
            useValue: 'large'
        },
        {
            provide: BUTTON_ICON_HINT_TOKEN,
            useValue: 'lg'
        },
        {
            provide: BUTTON_TOOLTIP_HINT_TOKEN,
            useValue: false
        },

    ]
})
export class AppPageHeaderComponent {
Enter fullscreen mode Exit fullscreen mode
@Component({
    selector: 'app-table',
    templateUrl: './template-file.html',
    providers: [
        {
            provide: BUTTON_SIZE_HINT_TOKEN,
            useValue: 'sm'
        },
        {
            provide: BUTTON_ICON_HINT_TOKEN,
            useValue: 'sm'
        },
        {
            provide: BUTTON_TOOLTIP_HINT_TOKEN,
            useValue: true
        },

    ]
})
export class TableComponent {
Enter fullscreen mode Exit fullscreen mode
@Component({
    selector: 'app-card-header',
    templateUrl: './template-file.html',
    providers: [
        {
            provide: BUTTON_SIZE_HINT_TOKEN,
            useValue: 'medium'
        },
        {
            provide: BUTTON_ICON_HINT_TOKEN,
            useValue: 'md'
        },
        {
            provide: BUTTON_TOOLTIP_HINT_TOKEN,
            useValue: false
        },

    ]
})
export class AppCardHeaderComponent {
Enter fullscreen mode Exit fullscreen mode

After doing this, we'll not have to specify buttonSize, buttonIconSize and showToolTip flag while using the app-button because the button component will get that from the context itself.

Please do let me know how you find this approach!

Thank you!

Top comments (0)