---
# System prepended metadata

title: Advanced Widgets Development in ThingsBoard

---

# Advanced Widgets Development in ThingsBoard

>[!Note]
>Provide simple examples demonstrating advanced widget features.

[toc]

## HTTP Service
* Use Angular httpClient
* Include ThingsBoard access token
```javascript
self.ctx.http.get(url)
        .subscribe(
            (res) => {
                console.log(res);
            },
            (err) => {
                alert(
                    `Error Status ${err.status}. ${err.error.message}`
                );
            });
```

## Broadcast Service
![image](https://hackmd.io/_uploads/SyW_lX3oye.png)

* broadcast widget
```html
<div class="input-box">Data:&nbsp;
    <input type="text" name="txt" id="txt" [(ngModel)]="inputTxt" />
</div>
<div class="btn" (click)="transferTxt()">Click to transfer data</div>
```
```javascript
self.onInit = function() {
    let $scope = self.ctx.$scope;
    $scope.inputTxt = '123';
    self.ctx.broadcastService = $scope.$injector.get(self.ctx.servicesMap.get('broadcastService'));
    $scope.transferTxt = transferTxt;
    function transferTxt() {
        self.ctx.broadcastService.broadcast('TEXT', $scope.inputTxt);
    }
}
```
* subscribe widget
```htmlembedded
<div>{{ widgetText }}</div>
```
```javascript
self.onInit = function() {
    let $scope = self.ctx.$scope;
    $scope.widgetText = 'Please click button in the left widget.';
    self.ctx.broadcastService = $scope.$injector.get(self.ctx.servicesMap.get('broadcastService'));
    self.ctx.broadcastService.on('TEXT', (event, args) => {
        $scope.widgetText = args[0];
        self.ctx.detectChanges();
    });
}
```


## Custom timeWindow
* ==Time-Series== Widget Only
* Start Time: `self.ctx.timeWindow.minTime` (millisecond)
* End Time: `self.ctx.timeWindow.maxTime` (millisecond)
* Time Zone: `self.ctx.timeWindow.timezone`

```javascript
    function updateTimeWindow(startTime, endTime) {
        const newDashboardtimewindow = {
            aggregation: {
                limit: 25000,
                type: "NONE"
            },
            hideAggInterval: false,
            hideAggregation: false,
            hideInterval: false,
            history: {
                historyType: 1,
                fixedTimewindow: {
                    startTimeMs: startTime,
                    endTimeMs: endTime,
                }
            },
            selectedTab: 1
        };
        self.ctx.dashboard
            .dashboardTimewindowChangedSubject.next(
                newDashboardtimewindow);
    }
```

### Subscribe dashboard timeWindow change
```javascript
self.onInit = function() {
    self.ctx.$scope.timeSubscribe = self.ctx.dashboard.dashboardTimewindowChanged;
    self.ctx.$scope.timeSubscribe.subscribe(
            (timewindow) => {
                console.log(
                    'dashboard timewindow changed!')
                console.log(timewindow);
            }
        );
};

self.onDestroy = function() {
    self.ctx.$scope.timeSubscribe.unsubscribe();
}
```

## Custom Dialog
```htmlmixed
<button (click)="openDialog()">Open a dialog</button>
```

```javascript
self.onInit = function() {
    self.ctx.$scope.openDialog = openDialog;

    const $injector = self.ctx.$scope.$injector;
    const customDialog = $injector.get(self.ctx.servicesMap.get('customDialog'));

    function openDialog() {
        customDialog.customDialog(htmlTemplate,
            dialogController).subscribe();
    }

    var htmlTemplate = `
    <div class="dialog-container" style="width: 200px; height: 150px; padding: 24px 12px; position: relative;">
        <h5 style="text-align: center; font-size: 16px; font-weight: 550; margin-bottom: 24px; color: #584e4e;">Custom Dialog</h5>
        <div class="wrap" style="display: flex; justify-content: center; align-items: center;">
          <div>Hello World</div>
        </div>
        <span (click)="cancel()" class="material-icons" style="cursor: pointer; position: absolute; top: 4px; right: 4px; color: #584e4e;">close</span>
    </div>
    `;

    function dialogController(instance) {
        let ct = instance;
        ct.cancel = function() {
            ct.dialogRef.close(null);
        };
    }
}
```


## Navigation
* Use `self.ctx.stateController.openState(id: string, params?: StateParams, openRightLayout?: boolean);` 
-> navigate to another page (dashboard state) 
```javascript
self.ctx.stateController.openState('dashboard_state_id', {}, false);
```

## Dashboard State in Widget (State in State)
* Dashboard states can be put inside a widget.

```html
<!-- Custom Widget -->
<tb-dashboard-state [ctx]="ctx"
  stateId="dashboard_state_id"
  class="dashboard-state">
</tb-dashboard-state>
```

## Settings Schema

```htmlembedded
<div class="box-wrap">
    <div>Show text:&nbsp;&nbsp;<span style="color: blue;">{{ text }}</span></div>
    <div class="box box1" style="background: {{box1Color}};">Box1</div>
    <div class="box box2" style="background: {{box2Color}};">Box2</div>
</div>
```

```javascript
self.onInit = function() {
    const settings = self.ctx.settings;
    self.ctx.$scope.text = settings.text || "text";
    self.ctx.$scope.box1Color = settings.box1Color || '#e89623';
    self.ctx.$scope.box2Color = settings.box2Color || '#8FC0DA';
}
```

```json
//Settings Schema
{
    "schema": {
        "type": "object",
        "title": "Settings",
        "properties": {
            "text": {
                "title": "text",
                "type": "string",
                "default": "text"
            },
            "box1Color": {
                "title": "Box1 Color",
                "type": "string",
                "default": "#e89623"
            },
            "box2Color": {
                "title": "Box2 Color",
                "type": "string",
                "default": "#8FC0DA"
            }
        }
    },
    "form": [
        "text",
        {
            "key": "box1Color",
            "type": "color"
        },
        {
            "key": "box2Color",
            "type": "color"
        }
    ]
}
```
