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 portal
  • display_name - The name that appears in the list of available widgets
  • description - A text description of the widget’s function
  • settings - 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 - varchar
  • number - integer, double, float
  • data - Links the widget to a portal’s datasource
    • outgoing_parser - Flag to signify the widget should have an outbound parser
    • incoming_parser - Flag to signify the widget should have an inbound parser
    • multi_input - Flag specifying if multiple datasources can be triggered
    • force_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.

  • 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) or cdn.rawgit.com (production)