Custom Widget (iFrame)

Hello everyone,
In this tutorial I’ll explain the ins and outs of Custom widgets, as well as how to build one yourself.

The new custom widgets type is now available in the latest version; this type allows you to create a widget with custom content and then display it on your dashboards. To learn more about Custom widgets, click here.

In the following paragraphs, I’ll teach you how to build your own Custom widget. Before you proceed, I recommend that you read about the specifications of this type of widget in our help center.


Creating your own

You can build your widget using any kind of web technology, such as Angular, React, Vue, or even plain old Javascript.

For the sake of simplicity, I’ll be using plain old Javascript, HTML and css. For a text editor I’ll be using Visual Studio Code version 1.44.2, but you can use even the simplest of text editors and follow along.

The screenshot below is the smallest working example of a Custom widget.

Don’t worry if you find this challenging, we’ll go step-by-step and understand the code together. The code in the screenshot above will produce the following result:

Apr-27-2020 17-14-49

As you can see, we’ve created a simple button. Once the button is pressed, a random decimal value will be sent to the Dynamic Table.

To download this sample HTML file, click here (Right and click -> Save as).


Step-by-step

Let’s walk this through step-by-step and understand our code.

These first two lines are just setting up our structure, telling the browser that the language is english and that the content of this file is html.

Here we define the configuration for the html file. There are two <meta> tags, the first one allows the use of accents in your texts (e.g. é, á, í), and the second one allows your widget to be correctly visualized in a mobile browser.

[IMPORTANT] The <script> tag tells the browser that this html file will use an external script; in this case, the external script is the TagoIO toolkit. In summary, this toolkit allows you to connect and communicate from your widget to TagoIO.

The <title> is used by the browser in case the widget goes fullscreen. This does NOT define the title of widget in the dashboard.

Here we define the initial <body> tag, which is used in html to signal we are about to start displaying content on the user’s screen.

The first tag after the <body> is the <button> tag. This tag will display a button in the page with the text inside of it, which in this case is “Send data”.

You may have noticed that there is a property called onclick in the button, this property is a function, and it is called every time the button is pressed. We’ll use this event to insert the random decimal value into our bucket.

Next up, we have the start of another <script> tag; you will notice that this tag is a bit different than the last one, because this one has content inside of it. When you put code inside of an html <script>, you’re telling the browser that this script is not external, in fact, it’s right here.

Highlighted in the screenshot above, you will see that we have created a new Javascript function called sendData, which should be the same name as the onclick event we defined in our button earlier. This function will be executed whenever the user presses our button.

In this sendData function, we are creating a JSON object and using the window.TagoIO.sendData function to send our JSON over to TagoIO.

Keep in mind that the window.TagoIO.sendData function only works because we requested it in our first <script> tag, over on line 6 of the html file.

Here we define the onStart event of our widget, and this event will fire whenever the user enters to see the dashboard. The first parameter received by this event is the widget object, this object will have all the properties of your custom widget, such as the title, parameters, variables, and more.

A good use of this function is to “save” the widget object globally, which is what we are doing in the highlighted code. You will notice we execute the code window.widget = widget, which means that we are saving the widget object globally so we can use it later.

Believe or not, this last screenshot ties the whole code together. This is the heart of your Custom widget.

Your custom widget will only appear on the screen if you call the window.TagoIO.ready() function, which means that you control whenever your widget is displayed.

We made the code like this because there were some cases where you had to perform a calculation or a request, and only then display the widget.

Until you call the ready function, your widget will keep loading, like this:

image

That’s it! That’s all the code you need to build your own widget. The next step is publishing it to acquire a link.


Publishing your widget

Now that you finished your widget, let’s publish it! The easiest way to publish your Custom widget is by using our Files page. To go there, press the Files button on the sidebar.

image

On the Files page, press the Upload File button in the top right corner:

image

Now select your HTML file and press upload; once your file is uploaded, select it and press Copy Url in the top right corner.

Next up, we have to create our widget. Head over to a dashboard, add a new widget, and select the Custom widget option, which looks like this:

image

Once you are inside of the Custom widget configuration, you should set its title and the link. The link will be the url that you just copied from the Files page.

Every variable that was used in the HTML code should be added to the widget’s configuration. For instance, if you used the variable my_variable in your HTML code, you should also add this variable to your widget’s configuration.

The configuration for your custom widget should look something like this:


That’s it! Your Custom widget should now be up and running. Once again, I recommend that you take a look at the overview documentation about the Custom widget over on our help center.

3 Likes

Hello, Great explanation, however I trying to retrieve data to my custom widget, however does not working!
In my code I have the followiing function:

function createBulletChart(parent, colorType) {
var colors = ["#19d228", “#b4dd1e”, “#f4fb16”, “#f6d32b”, “#fb7116”];

/* Create chart instance */
var chart = container.createChild(am4charts.XYChart);
chart.paddingRight = 25;

Here is add data to show in the custom widget
/* Add data */
chart.data = [{
“category”: “Evaluation”,
“value”: 65, (fix value) —> this correct retrive from tago.
“target”: 78
}];

I invoked the :

window.TagoIO.onStart((widget) => {
window.widget = widget;
});

        window.TagoIO.ready();

But is not workinh, may I help?

BR

TS

THanks @alinetusi for support, I got to show the custom widget in my dashboards however the widget custom is not bring the data from variable set, look my configurantion enviroment:

Hi @tulio.souza,
As we treated in the support, I’m going the resume all we talked about it, my goal is to help other people who may have the same issue.

First, we noticed that you didn’t start the connection with TagoIO to begin receiving data. This communication can be done using:
window.TagoIO.ready();

Second, the function window.TagoIO.onStart don’t run immediately, that’s why the parameter value is not sent out from the callback. You can use this function to start your chart. The variable data comes in a function called: window.TagoIO.onRealtime

The function to start the chart (window.TagoIO.onStart), only brings basics information about the widget. The parameter fields are used to send extra information about the custom widget, for example, secret keys, URL, etc.

@alinetusi Is there a reference documentation for the API used in the custom widget? Thanks.

Hi @sanimesa,
Not exactly, this is the most complete post about the custom widget. However, we have more documentation mostly about the structure.
Here is the links: Custom Widget Overview
Custom Widget Parameters

Please, let me know if this helps you.

@alinetusi It would help to know the details of the onStart and onRealTime methods, particularly the definitions of the widget and widgetdata parameters respectively that are fed into these methods.

Thanks.

I hope this helps

widget = { // widget information, does not return value of variables
  "id": string, // widget id
  "label": string, // card title
  "display": {
    "header_buttons": [],
    "parameters": [ // parameters can be passed through the Parameters tab in the IFrame edition
      {
        "key": string,
        "value": string,
      },
    ],
    "url": string, // iframe url
    "user": {
      "id":  string, // user id
      "name": string, // user name
      "timezone": string,
      "type": "account" | "run_user", // admin or run
      "options": { // account preferences
        "date_format": string,
        "time_format": string,
      }
    },
    "variables": [
      {
        "bucket": {
          "id": string, // bucket id
          "name": string // bucket name
        },
        "origin": {
          "id": string, // device id
          "name": string, //device name
          "bucket": string, // bucket id
        },
        "variable": string, // variable name
      }
    ]
  },
  "type": "iframe",
}

widgetData = [
  { // each object in the widgetData array is a bucket
    "data": {
      "bucket": string, // bucket id
      "origin": string, // device id
      "timezone": string,
      "variables": string[], // selected variables that are in that bucket
      "query": string,
    },
    "result": [ // each result information corresponds to the value of a variable, ordered by time
      {
        "id": string, // variable id
        "origin": string, // device id
        "time": string,
        "serie": string,
        "metadata": any,
        "location": { // optional
          "type": string,
          "coordinates": number[] // [lng, lat]
        },
        "unit": string,
        "value": string,
        "variable": string, // variable name
      },
    ],
  },
]

Just trying to understand the structure a bit better.
Regarding the WidgetData, I am building a dashboard widget similar to the Icon widget only meant to be more responsive.
Is there an easy way to access the newest value for a variable without having to search for it in the result array?
Any additional information about this would be very much appreciated

Hi @rakel, there is no other way to get the new value.
You can use this function to search for the last data whenever a new array arrives

function getLastValueByVariable(widgetData, variable) {
    let lastData = {};

    widgetData.forEach((item) => {
      lastData = item.result.find((e) => e.variable === variable) || {};
    });
    return lastData;
}
const value = getLastValueByVariable(widgetData, "variable_name");
console.log(value)

Thank you for this, it is very helpful :slight_smile:

1 Like

Dear Team,

I am trying to create a widget with two buttons and to send two variables in each button.

I have tried the code which you have demonstrated, but i am not getting the output.

I will post my code here.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script type="text/javascript" src="https://admin.tago.io/dist/custom-widget.min.js"></script>
        <title>My Widget</title>
        <style>
	.button {
  	border: none;
  	color: white;
  	padding: 30px 37px;
  	text-align: center;
  	text-decoration: none;
  	display: inline-block;
  	font-size: 20px;
	font-family: New Tegomin;
  	margin: 4px 2px;
  	cursor: pointer;}
	.button1 {background-color: #4CAF50;color: black} /* Green */
	.button1:hover {background-color:#006400 ;color: white;} /* Dark Green */
	.button2 {background-color: #FF0000;color: black} /* Red */
	.button2:hover {background-color: #8B0000;color: white;} /*Dark Red */
    </style>    
    </head>
    <body>
        <button class="button button1"; onclick="sendData()">Open</button>
        <button class="button button2"; onclick="sendDa()">Close</button>

        <script>
            var data;
            function sendData() {
                data = {
                    variable1: "form_payload",
	    value1: "01",
	    variable2: "form_port",
	    value2: "01",
                };
                window.TagoIO.sendData(data);
	}
	
	function sendDa() {
                data = {
                    variable1: "form_payload",
	    value1: "00",
	    variable2: "form_port",
	    value2: "01",
                };
                window.TagoIO.sendDa(data);
	}

            window.TagoIO.onStart((widget) => {
                window.widget = widget;
            });

            window.TagoIO.ready();
        </script>
    </body>
</html>

If any one can help me on this?

Thank you in advance.

Hello @surendar
To send multiple data you need to send it as an array:

data = [
     {
        variable: "form_payload",
        value: "01",
     },
     {
        variable: "form_port",
        value: "01",
     }
]
window.TagoIO.sendData(data);

and in the second function you wrote:

window.TagoIO.sendDa(data);

the correct one is window.TagoIO.sendData(data);

testecli

fixed code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script type="text/javascript" src="https://admin.tago.io/dist/custom-widget.min.js"></script>
        <title>My Widget</title>
        <style>
	.button {
  	border: none;
  	color: white;
  	padding: 30px 37px;
  	text-align: center;
  	text-decoration: none;
  	display: inline-block;
  	font-size: 20px;
	font-family: New Tegomin;
  	margin: 4px 2px;
  	cursor: pointer;}
	.button1 {background-color: #4CAF50;color: black} /* Green */
	.button1:hover {background-color:#006400 ;color: white;} /* Dark Green */
	.button2 {background-color: #FF0000;color: black} /* Red */
	.button2:hover {background-color: #8B0000;color: white;} /*Dark Red */
    </style>    
    </head>
    <body>
        <button class="button button1"; onclick="sendData()">Open</button>
        <button class="button button2"; onclick="sendDa()">Close</button>

        <script>
            var data;
            function sendData() {
                data = [
                    {
                        variable: "form_payload",
                        value: "01",
                    },
                    {
                        variable: "form_port",
                        value: "01",
                    }
                ]
                window.TagoIO.sendData(data);
	        }
	
	        function sendDa() {
                data = [
                    {
                        variable: "form_payload",
                        value: "00",
                    },
                    {
                        variable: "form_port",
                        value: "01",
                    },
                ]
                window.TagoIO.sendData(data);
            }

            window.TagoIO.onStart((widget) => {
                window.widget = widget;
            });

            window.TagoIO.ready();
        </script>
    </body>
</html>

I hope this helps :wink:

Dear Gustavo,

Thank you, your code is working fine.

1 Like

Any idea how to retrieve data from the bucket and use it in the custom widget?

Hi @iotfencesensor
The bucket data arrives from the function

window.TagoIO.onRealtime((data) => {
     // here you can manipulate the data
});

you can use the function I wrote above to get the last data

<script type="text/javascript" src="https://admin.tago.io/dist/custom-widget.min.js"></script>
<div id="myDiv" style="width: 100%; height: 100%;"></div>
<script>
    function getLastValueByVariable(widgetData, variable) {
        let lastData = {};

        widgetData.forEach((item) => {
        lastData = item.result.find((e) => e.variable === variable) || {};
        });
        return lastData;
    }

    window.TagoIO.onRealtime((data) => {
        const myvar = getLastValueByVariable(data, "variable_name");
        const e = document.getElementById("myDiv");
        e.innerHTML = myvar.value;
    });
    window.TagoIO.ready();
</script>

In this code the last data of the variable variable_name appears in the widget. I hope it helps