Using a multi-value component, we'll explore how you can write a component that renders multiple metrics from an Internet of Things device in a room using Kendo UI Builder.
In the previous blog of my Kendo UI Builder series, I showed you how to render a single metric obtained from a REST service. Today, I'll demonstrate how write a component that renders multiple metrics from an Internet of Things device in a room. The data from the various rooms and devices is obtained via a REST data provider.
This sample will show us the difference between single-value and multi-value components via usage of the Value Primitive property in the component definition file.
If you have not read the blog on how to use a single-value component, now’s the time to do so to ensure you have the proper context.
The view containing the combo-box and the custom component looks like this:
To follow along, download the template samples zip from github or clone the repository https://github.com/thierryciot/kendoui-builder-template-samples; open folder components/custom-device-multiple-metrics-comp and follow the same step outlined in this post to install this template in your target application.
Prerequisites
We need:
- The REST service and the associated IoT Data provider configured in the previous blog.
- A blank view containing a combo-box to select which room we want information from.
For both, please check the detailed instructions in the prerequisites section of this blog.
Note: You can reuse the application and blank view from the previous blog. Simply drag the multiple metrics custom component to a separate row.
Component Definition
Open the file components/custom-device-metrics-comp/custom-device-multiple-metrics-comp.json.
The main difference with the single-value device metric component is that the valuePrimitive property is defined as false and we define the dataSourceName property:
01.
"valuePrimitive"
: {
02.
"type"
:
"boolean"
,
03.
"default"
:
false
,
04.
"hidden"
:
true
,
05.
"order"
: 3
06.
},
07.
08.
"dataSourceName"
: {
09.
"type"
:
"string"
,
10.
"default"
:
""
,
11.
"hidden"
:
true
,
12.
"order"
: 4
13.
},
When valuePrimitive is false, the full model is made available in the EJS expression <%-model%>, for example, dataSourceModel1. When valuePrimitive is true, as we saw in the previous blog, <%- model %> resolves to the model name and the field name, for example, dataSourceModel1.hum
Here is how the property panel renders:
Additionally, to get multi-value working, the Kendo UI Builder code generator needs the dataSourceName, so we define it as a hidden property.
Design Time
See file components/custom-device-multiple-metrics-comp/design-time/template.html.ejs.
We simply output a list of all the metrics with hard-coded values to give the user a sense of the overall aspect:
<
ul
style
=
"padding-left: 1.5rem;"
>
<
li
>Current Temperature: 23</
li
>
<
li
>Set Temperature: 22</
li
>
<
li
>Humidity: 65%</
li
>
<
li
>CO2: 145</
li
>
<
li
>VOC: 50</
li
>
</
ul
>
Run-Time
Angular
See file components/custom-device-multiple-metrics-comp/angular/template.html.ejs:
<% if ( model === "" ) { %>
<
div
>Please select a model to use this component.</
div
>
<% } else { %>
<
div
style
=
"margin-top: 1rem;"
>
{{$config.components.<%-id%>.metric}}:
<
ul
style
=
"margin-top: 0.8rem; padding-left: 1.5rem;"
>
<
li
style
=
"margin-top: 0.6rem;"
>
Current Temperature: {{$dataModels.<%- model %>.currentTemp}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
Set Temperature: {{$dataModels.<%- model %>.setTemp}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
Humidity: {{$dataModels.<%- model %>.hum}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
CO2: {{$dataModels.<%- model %>.co2}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
VOC: {{$dataModels.<%- model %>.voc}}
</
li
>
</
ul
>
</
div
>
We simply output a list of metrics. The data is obtained starting at $dataModels. This is defined in the generated code base component TypeScript file, for example, devices.view.base.component.ts. Note: the name can vary as it depends on how you name your view but the file suffix will be the same.
It is an object literal with a reference to an object containing the field values we want to render in component instances, for example:
public $dataModels: any = {
DevicesModel:
new
IoTDevice()
};
The IoTDevice class was auto-generated and looks like this:
export class IoTDevice {
public id: number;
public room: string;
public setTemp: number;
public currentTemp: number;
public hum: number;
public co2: number;
public voc: number;
}
AngularJS
See file components/custom-device-multiple-metrics-comp/angularjs/directive.html.ejs.
Here again, we output a list of metrics:
<%#
$viewModels is defined at the view level - see generated code in app\src\modules\custom-components\room-metrics\controller.js
%>
<
ul
style
=
"padding-left: 1.5rem;"
>
<
li
style
=
"margin-top: 0.6rem;"
>
Current Temperature: {{vm.$viewModels.<%-model%>.currentTemp}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
Set Temperature: {{vm.$viewModels.<%-model%>.setTemp}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
Humidity: {{vm.$viewModels.<%-model%>.hum}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
CO2: {{vm.$viewModels.<%-model%>.co2}}
</
li
>
<
li
style
=
"margin-top: 0.6rem;"
>
VOC: {{vm.$viewModels.<%-model%>.voc}}
</
li
>
</
ul
>
The generated code (app\src\modules\custom-components\room-metrics\controller.js) defines $viewModels as an array of data source models. The expression vm.$viewModels.<%-model%> will be translated by EJS compiler to vm.$viewModels.DevicesModel. From there, we can simply access all the metrics we need.
Conclusion
To write components that use multiple values from a data source, we need to define the “Value Primitive” property as false. This has an impact on the code generation process and in particular how the model is defined. Here is a summary of the syntax to access metrics depending on the valuePrimitive setting:
valuePrimitive=false
- AngularJS: {{vm.$viewModels.<%-model%>.currentTemp}}
- Angular: {{$dataModels.<%- model %>.currentTemp}}
valuePrimitive=true
- AngularJS: {{vm.$viewModels.<%-model%>}}
- Angular: {{$dataModels.<%-model%>}}
We now have learned how to create components that interact with the model defined at view level. In a future blog, we will see how to apply these skills to create a view where we can select a travel destination and show its name, rating and a map. As usual, stay tuned! 😊
Catch Up on Kendo UI Builder
If you jumped into this series in the middle and want to start from the beginning, you can find the previous blog posts here:
- Introduction to Kendo UI Builder Templates
- Behind the Scenes of Kendo UI Builder Templates
- Event Processing in Kendo UI Builder Templates
- Augmenting Models in Kendo UI Builder Templates
- Introduction to Custom Components for Kendo UI Builder
- Creating Kendo UI Builder Custom Components from Angular Components
- Creating a Custom Rating Component with Kendo UI Builder
- Displaying Metrics from IoT Devices with Kendo UI Builder
Thierry Ciot
Thierry Ciot is a Software Architect on the Corticon Business Rule Management System. Ciot has gained broad experience in the development of products ranging from development tools to production monitoring systems. He is now focusing on bringing Business Rule Management to Javascript and in particular to the serverless world where Corticon will shine. He holds two patents in the memory management space.