Custom Widgets
Walkthrough
To understand widget source structure, we will walk through the creation of a basic button widget.
- First create a javascript file:
myCustomWidget.js
Widget Schema
The first component of your widget is the schema delivered to the portal interface. Loaded at runtime, it contains meta information along with user editable settings relating to the widget’s function.
freeboard.loadWidgetPlugin({
"type_name" : "my_custom_widget",
"display_name": "My Custom Widget",
"description" : "A custom button widget",
"settings" : [
{
name : "container_width",
display_name : "Container width",
type : "integer",
description : "Width of your widget's container as a percentage. Useful when juxtaposing widgets.",
default_value : "100",
required : true
}
],
"newInstance" : function(settings, newInstanceCallback, updateCallback)
{
newInstanceCallback(new myCustomWidget(settings, updateCallback));
}
});
type_name
- A unique reference that will be used locally in the portaldisplay_name
- The name that appears in the list of available widgetsdescription
- A text description of the widget’s functionsettings
- The user editable settings. Included is the required ‘container_width’ attribute. (more details below)newInstance
- An initialization function that generates an instance of myCustomWidget
For this example we will add user settings that allow for customization of a button and link to an existing datasource.
Let’s add the following so that our settings include:
{
name : "buttonLabel",
display_name: "Button Label",
type : "text"
},
{
name: "eventTarget",
display_name: "Event Target",
type: "data",
outgoing_parser: true,
multi_input: true,
force_data: "dynamic"
},
{
name : "heightAdjust",
display_name : "height in blocks",
type : "number",
default_value: 4
},
{
name : "container_width",
display_name : "Container width",
type : "number",
description : "Width of your widget's container as a percentage. Useful when juxtaposing widgets.",
default_value : "100",
required : true
}
Every setting has a name
that is used within scope of the portal, a display_name
shown to users in the widget’s settings panel, type
for relevant value handling, a default_value
for initial states, and a required
flag to force user entry.
Setting types with relevant optionals:
text
- varcharnumber
- integer, double, floatdata
- Links the widget to a portal’s datasourceoutgoing_parser
- Flag to signify the widget should have an outbound parserincoming_parser
- Flag to signify the widget should have an inbound parsermulti_input
- Flag specifying if multiple datasources can be triggeredforce_data
- Do not allow a user to choose between data types. Options: “dynamic”, “static”
Widget Model
Now that we have a schema in place, a user can select and modify attributes of the widget. We will add a model that will be used to run the widget’s interaction within the portal. Below is the model scaffolding with required methods:
var myCustomWidget = function(settings, updateCallback) {
var self = this;
var currentSettings = settings;
self.render = function(containerElement){
// Outputs element to the DOM
}
self.getHeight = function(){
// Returns the block height of the widget. (A block is 60px)
return self.currentSettings.heightAdjust;
}
self.onSettingsChanged = function(newSettings)
{
// User has opened and saved settings
self.currentSettings = newSettings;
}
self.onCalculatedValueChanged = function(settingName, newValue)
{
// Called when a linked datasource updates. If multiple sources are linked (using different setting objects), handling can be filtered by checking settingName.
}
self.onDispose = function(){
// Removal from portal methods
}
self.getValue = function(){
// Used in parser to fetch value using `this.widget`
}
}
For the purpose of this example, we will render a basic html form button. When clicked a linked datasource will be sent whatever a user specifies in the outbound parser. One possible implementation is given below:
var myCustomWidget = function(settings, updateCallback)
{
var self = this;
var currentSettings = settings;
// Create a JQuery element refrence
var myButtonElement = $("<input>")
.attr({
type:"button",
value: settings.buttonLabel
})
.addClass("widget-button")
.wrap('<div></div>');
// Create a placeholder payload. Will be modified by datasource
var submitPayload = {};
self.render = function(containerElement)
{
// Add the button element to the DOM container
$(containerElement).append(myButtonElement);
// Add an event listner to fire the datasource event
myButtonElement.on( "click", self.onEvent);
}
self.getHeight = function()
{
// Validated block value using utils.widget.calculateHeight(int) ... Validates value type and range
return utils.widget.calculateHeight(currentSettings.heightAdjust);
}
self.onSettingsChanged = function(newSettings)
{
// Update settings
currentSettings = newSettings;
// Update possible UI changes
myButtonElement.val(newSettings.buttonLabel);
}
self.onCalculatedValueChanged = function(settingName, newValue)
{
// Called when a linked datasource updates. If multiple sources are linked (using diffrent setting objects), handling can be filtered by checking settingName.
// Update the payload with the last known DS value
submitPayload = newValue;
}
self.onDispose = function()
{
}
self.getValue = function()
{
return submitPayload;
}
self.onEvent = function() {
updateCallback(submitPayload);
}
}
Now that you have a functioning widget, upload your source to GitHub or file hosting server.
Link custom widget to portals
- Within the portals tab of your ClearBlade platform system, click ‘New’ and select plugin.
- In the name field, enter a ClearBlade platform reference name. Note that the name of the widget declared within your source will still be the name within your portal.
- In the URL field include the raw link to your hosted source code.
- If hosted on GitHub, you may need to change raw.githubusercontent.com to
rawgit.com
(non-production) orcdn.rawgit.com
(production)
- If hosted on GitHub, you may need to change raw.githubusercontent.com to