Cumulocity Web Development Tutorial - Part 4: Convert component into a widget
Tags: iot, tutorial, webdev, cumulocity
Published: 2023-03-07 15:15:38

---
title: Cumulocity Web Development Tutorial - Part 4: Convert component into a widget
published: true
date: 2023-03-06 10:42:52 UTC
tags: iot, tutorial, webdev, cumulocity
canonical_url: https://tech.forums.softwareag.com/t/cumulocity-web-development-tutorial-part-4-convert-component-into-a-widget/275224
---

 

## Welcome to the 4th round of the web development series.

![minion-boxing](https://global.discourse-cdn.com/techcommunity/original/3X/e/b/eb62e46b615fecf032c396b87a28ba546c3420bd.gif)

In the [last part](https://tech.forums.softwareag.com/t/cumulocity-web-development-tutorial-part-3-query-data-from-cumulocity/266388) you have integrated the [@c8y/client](https://www.npmjs.com/package/@c8y/client) from the Cumulocity Web SDK to communicate with Cumulocity’s API. In particular, you have learned how to query data from the [Inventory](https://cumulocity.com/guides/concepts/domain-model/#inventory) using the `InventoryService`. Among other, the Inventory stores your device data. To have some device data available in the Inventory of your Cumulocity instance, you have created a temperature simulator using the [simulator self-service feature](https://cumulocity.com/guides/users-guide/device-management/#simulator) in the Device Management application. The temperature simulator sends continuously temperature measurements. Using the `MeasurementService` from the `@c8y/client` you have queried the current temperature measurement. To always get the latest measurement from the simulator and display it in the UI you have integrated the `Realtime` service into your component. With these changes you could remove all previously mocked data from the `device-info` module and achieve a more dynamic behavior of the component.

In the 4th part of the web development series, the `device-info` component will be converted into a [Cumulocity widget](https://cumulocity.com/guides/web/tutorials/#add-a-custom-widget), which can then be used dynamically on Cumulocity dashboards.

## Add dashboarding to your application

Originally, dashboards are part of the [Cockpit application](https://cumulocity.com/guides/users-guide/cockpit/#dashboards). But you can integrate the dashboard feature in any of your custom applications, as the necessary component is part of the `@c8y/ngx-components` package. In this section, you will update your application and add a dashboard to it. You can continue with your project or use [part-03](https://github.com/SoftwareAG/cumulocity-web-development-tutorial/tree/main/part-03/my-c8y-application) from github. If you are struggling with part 4, you can find the final application in the corresponding [github project](https://github.com/SoftwareAG/cumulocity-web-development-tutorial/tree/main/part-04/my-c8y-application).

In the `src` directory create a new folder called `named-dashboard`. This folder will be home to your dashboard module. Create a new file for the template named `named-dashboard.component.html`.

**named-dashboard.component.html**

```
<c8y-title>Named dashboard</c8y-title>

<c8y-context-dashboard [name]="'My named dashboard'" [canDelete]="false"></c8y-context-dashboard>

```

The template consists of a `c8y-title` element to specify the title in the header. In addition, it uses the Cumulocity ContextDashboard component [c8y-context-dashboard](http://resources.cumulocity.com/documentation/websdk/ngx-components/components/ContextDashboardComponent.html) from `@c8y/ngx-components` to instantiate a new dashboard. In this case, the dashboard will be a named dashboard. This means the context of your dashboard is defined by its name and therefore will be identified by its name: `My named dashboard`. To learn more about context dashboards have a look at the tutorial application of Cumulocity. The tutorial application provides some examples for Cumulocity dashboards.

> **Important:** When you want to see the possibilities and implementation details of the Web SDK you should try the tutorial application. You can install it by running `c8ycli new <<your-app-name>> tutorial` .

Create the corresponding component and name the file `named-dashboard.component.ts`. The purpose of the component is to serve the previously created template:

**named-dashboard.component.ts**

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

@Component({
  selector: 'named-dashboard-component',
  templateUrl: './named-dashboard.component.html',
})
export class NamedDashboardComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}

```

You will need a navigation factory to add a navigation entry to the left side menu to navigate to your dashboard. Create a new navigation factory called: `named-dashboard.factory.ts`.

**named-dashboard.factory.ts**

```
import { Injectable } from '@angular/core';
import { NavigatorNode, NavigatorNodeFactory } from '@c8y/ngx-components';

@Injectable()
export class NamedDashboardNavigationFactory implements NavigatorNodeFactory {
  get() {
    return new NavigatorNode({
      label: 'Dashboard',
      icon: 'robot',
      path: 'named-dashboard',
      priority: 50,
    });
  }
}

```

In the `NamedDashboardNavigationFactory` you will register a new `NavigatorNode`, which forwards the user to your dashboard component via the path `named-dashboard`.

Finally, you need to create the module for your new dashboard component. Create the additional file `named-dashboard.module.ts` in your `named-dashboard` folder:

**named-dashboard.module.ts**

```
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CoreModule, HOOK_NAVIGATOR_NODES } from '@c8y/ngx-components';
import { ContextDashboardModule } from '@c8y/ngx-components/context-dashboard';
import { NamedDashboardComponent } from './named-dashboard.component';
import { NamedDashboardNavigationFactory } from './named-dashboard.factory';

const routes: Routes = [
  {
    path: '',
    redirectTo: 'named-dashboard',
    pathMatch: 'full',
  },
  {
    path: 'named-dashboard',
    component: NamedDashboardComponent,
  },
];

@NgModule({
  imports: [
    ContextDashboardModule.config(),
    CommonModule,
    RouterModule.forChild(routes),
    CoreModule,
    ContextDashboardModule,
  ],
  exports: [],
  declarations: [NamedDashboardComponent],
  providers: [
    { provide: HOOK_NAVIGATOR_NODES, useClass: NamedDashboardNavigationFactory, multi: true },
  ],
})
export class NamedDashboardModule {}

```

The module imports the `ContextDashboardModule` from `@c8y/ngx-components` to provide the dashboard feature for your application. Furthermore, the `NamedDashboardNavigationFactory` is registered and provided using the `HOOK_NAVIGATOR_NODES`. The path `named-dashboard` defined in the `NamedDashboardNavigationFactory` will be connected to the `NamedDashboardComponent` by using the `RouterModule`.

Finally, update the `AppModule` and import your `NamedDashboardModule`:

```
import { NamedDashboardModule } from './src/named-dashboard/named-dashboard.module';

@NgModule({
  imports: [
    ...
    NamedDashboardModule,
  ],
  bootstrap: [BootstrapComponent],
})
export class AppModule {} 

```

If you start your application, you will see a new navigation entry in the left side navigation to access the named dashboard component

[![image](https://global.discourse-cdn.com/techcommunity/optimized/3X/d/b/db722edaf118da6d33336ebc7756c94035a2a29f_2_690x338.png)](https://global.discourse-cdn.com/techcommunity/original/3X/d/b/db722edaf118da6d33336ebc7756c94035a2a29f.png "image")

For now, you can’t add any widgets to the dashboard, because the list of widgets is empty. You are going to change this by converting the `device-info` component to a widget.

## Convert the `device-info` component into a c8y widget

Let’s update the `DeviceInfoComponent` component in the `device-info` directory. First, remove the `device-info.factory.ts` file from the project. The `DeviceInfoNavigationFactory` isn’t needed anymore, as the component should be used on the dashboard in the future.

Update the `device-info.module.ts`. Remove the `DeviceInfoNavigationFactory` and the routes (including the `RouterModule` and the corresponding imports) from it. Now, add the widget configuration to the module. The widget configuration is provided using the hook `HOOK_COMPONENTS` from `@c8y/ngx-components`.

**device-info.module.ts**

```
...
import { CoreModule, DynamicComponentDefinition, HOOK_COMPONENTS } from '@c8y/ngx-components';
import { ContextWidgetConfig } from '@c8y/ngx-components/context-dashboard';
...

@NgModule({
  imports: [CoreModule],
  exports: [],
  declarations: [DeviceInfoComponent],
  providers: [
    {
      provide: HOOK_COMPONENTS,
      multi: true,
      useValue: [
        {
          id: 'device-info.widget',
          label: 'Device Info Widget',
          description: 'This is a sample widget',
          component: DeviceInfoComponent,
          data: {
            settings: {
              noNewWidgets: false,
              ng1: {
                options: {
                  noDeviceTarget: false, 
                  groupsSelectable: false,
                },
              },
            },
          } as ContextWidgetConfig,
        },
      ] as DynamicComponentDefinition[],
    },
  ],
})
export class DeviceInfoModule {}

```

In the configuration of the widget, you define following properties:

- `id` - unique identifier for you widget
- `label` - used as the title in the widget catalog
- `description` - used as the description in the widget catalog
- `component` - the component, which should be used for the widget. You define the `DeviceInfoComponent` as the relevant component.

In the data property, you can define some basic configuration for your widget

- `noDeviceTarget` - set to false if a you want to enable the device selector for your widget
- `groupsSelectable` - set to true if groups should be selectable as well

In case of the `device-info` widget, you will enable device selection, but disable group selection.

Next you need to update the `DeviceInfoComponent` to correctly receive the configuration, if the component is added as a widget to the dashboard. Remove the hardcoded device id from the component. Instead add a new variable called `config` for the configuration of your widget, which is marked as `Input()` in your component. This variable `config` is automatically set, when the configuration for your widget is completed and the widget has been added to the dashboard.

**device-info.component.ts**

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

export class DeviceInfoComponent implements OnInit {
  @Input() config: { device: { id: string; name: string } };
  
  ...
  
  private async initDeviceDetails() {
    this.deviceDetails = await this.deviceInfoService.getDeviceDetails(this.config.device.id);
  }

  private subscribeForTemperatureMeasurements() {
    this.deviceInfoService.temperatureMeasurement$.subscribe(
      (temperatureMeasurement) => (this.tempteratureMeasurement = temperatureMeasurement)
    );

    this.deviceInfoService.subscribeForTemperatureMeasurements(this.config.device.id);
  }

```

Instead of using the hardcoded device id for the method calls `this.deviceInfoService.getDeviceDetails()` and `this.deviceInfoService.subscribeForTemperatureMeasurements()`, you will use the id of the device, which has been selected as an input for your widget: `this.config.device.id`.

Lastly, you will update the template for your `device-info` widget. Simply remove the `card` class from the root `<div>` element:

**device-info.component.html**

```
<div class="p-l-16 p-r-16" *ngIf="deviceDetails">
  ...
</div>

```

The `card` class is removed, because if your `device-info` widget is added to a dashboard, it will automatically be wrapped in a `card` element.

Run your application locally and add your newly created widget to the `named dashboard`. Select your temperature simulator as an input device for your widget.

![widget-dashboard](https://global.discourse-cdn.com/techcommunity/original/3X/8/c/8c8e33595ccf05cc7014695558a3a6e86221da8f.gif)

## Conclusion

Great, you have successfully converted the `device-info` component into a widget, which now can be used on Cumulocity dashboards. You can view the full code for part 4 in the corresponding [github](https://github.com/SoftwareAG/cumulocity-web-development-tutorial/tree/main/part-04/my-c8y-application) project.

![The Fresh Prince Of Bel Air Carlton Dance GIF by HBO Max](https://global.discourse-cdn.com/techcommunity/original/3X/f/3/f367a29952bc9e84cf09e174478109f7e76e8525.gif)

In part 5 we will have a look at the newly introduced Micro-Frontend framework and learn how the `device-info` widget can be provided as UI plugin to be used in the Micro-Frontend framework. Check out [this article](https://tech.forums.softwareag.com/t/the-power-of-micro-frontends-how-to-dynamically-extend-cumulocity-iot-frontends/266665) to get a first introduction.

Until next time ![:wave:](https://emoji.discourse-cdn.com/twitter/wave.png?v=12 ":wave:")


[Read full topic](https://tech.forums.softwareag.com/t/cumulocity-web-development-tutorial-part-4-convert-component-into-a-widget/275224)