Documentation

Ucommerce includes full API reference documentation and lots of helpful articles to help you build your e-commerce site as effortlessly as possible.

Topics Payment Providers
v7.18

Create a widget in Ucommerce

In the following article, you will learn how to easily create a new widget to be configured in any of the dashboards available.

Whether you want a new view in Google Analytics, Integration for Gecko boards, information coming from a web service - the recipe is the same.

Configuration for the widget

Before getting started building the widget, here are a few configuration options to consider before coding away.

The configuration below is one of the sample widgets shipped below. Common for all widgets configured for Ucommerce is that they always use the same component configured in our Windsor container.

    
    
    <component
    	id="GoogleAnalyticsPageViews"
    	service="Ucommerce.Presentation.UI.Widget, Ucommerce.Presentation"
    	type="Ucommerce.Presentation.UI.Widget, Ucommerce.Presentation">
    	<parameters>
    
    	</parameters>
    </component>
    
    

The parameters you can configure is the different properties for your widget, making the end result look something similar to the configuration below. All widgets should use the component above for configuration. The only thing that should change is the id used for Castle Windsor. If the same id is used for two components you will override a component and it will no longer be available.

    
    
    <component
    	id="GoogleAnalyticsPageViews"
    	service="Ucommerce.Presentation.UI.Widget, Ucommerce.Presentation"
    	type="Ucommerce.Presentation.UI.Widget, Ucommerce.Presentation">
    	<parameters>
    		<Properties>
    			<dictionary>
    				<entry key="googleAnalyticsKey"></entry>
    				<entry key="chartType">LINE</entry>
    				<entry key="metrics">ga:sessions</entry>
    				<entry key="dimensions">ga:date</entry>
    			</dictionary>
    		</Properties>
    		<Name>Google Analytics Page visits</Name>
    		<View>/Apps/Widgets/analyticsDataChart/view.html</View>
    		<EditView>/Apps/Widgets/analyticsDataChart/edit.html</EditView>
    		<ShowLoadingCover>True</ShowLoadingCover>
    		<EnableReload>True</EnableReload>
    		<Css>
    			<array>
    				<value>/Apps/Widgets/analyticsDataChart/analyticsStyle.css</value>
    			</array>
    		</Css>
    		<Javascript>
    			<array>
    				<value>/Apps/Widgets/analyticsDataChart/analyticsDataChart.controller.js</value>
    				<value>/Apps/Widgets/analyticsDataChart/AnalyticsDataChart.js</value>
    			</array>
    		</Javascript>
    	</parameters>
    </component>
    
    

Valid parameters to configure is:

Parameter Type Details
Properties Dictionary Dictionary of key values you can access in your widget. Could be a google analytics key or similar
Name string Unique name of your widget. Displayed in the drop down when the user adds a widget.
View .html file The content displayed inside the widget. Must point to a .html file.
EditView .html file The view to display when the dashboard is in edit mode.
ShowLoadingCover True/False Shows a generic loading symbol when your widget loads or reloads.
EnableReload True/False Shows a drop down in the top of the widget allowing you to reload the content of your widget. Actions will be similar to the widget loading for the first time.
Css .css file[] Array of CSS files your widget depends on. Will be included in the order they are supplied.
Javascript .js file[] Array of javascript your widget depends on. Will be included in the order they are supplied.

Please note that all files (.html,.js, and .css) are relative virtual paths to the ucommerce folder under the CMS in the website. You cannot use '~' or '../' to navigate.

Creating an "Orders placed per day"-Widget

In this example, we will create a new widget that enables the user to see how many orders has been placed by grouping them by dates and allowing to scroll through time. To help us along we'll use a great and powerful javascript framework that can create all sorts of beautiful Graphs and drawings called visjs. .

Besides that, we also need a web service that can deliver the said data. If you're interested in how to build that using Ucommerce, please read the article on How to create a web service

The data for my widget may, of course, come from any source or any web service.

Now we're ready to write some awesome code.

Basically, the widget framework will take the content of our view file (view.html) and render that. Since the framework is written in AngularJS, we can leverage that and create a directive and a controller that will serve as the actual content. So the view of our file will only look like this.

    
    	<orders-by-dates></orders-by-dates>
    

So the widget framework will output <orders-by-dates></orders-by-dates> and if we can hook into the angular application it will be transformed into the view of our directive. This is where the list of JS files configured for our widget comes in handy. All assets to widgets will be loaded in when the page loads before widgets are initialized. This gives us enough time to register our directives and controllers needed for the widget.

We'll start out by registering the controller like so:

    
    function ordersByDatesController($scope, $http,$timeout) {
    	
    }
    
    angular.module('ucommerce').controller("ordersByDatesController", ordersByDatesController);
    

Next up we'll register the directive that has the ordersByDatesController as a dependency:

    
    function ordersByDates() {
        return {
            restrict: 'E',
            transclude: true,
            replace: true,
            scope: true,
            templateUrl: UCommerceClientMgr.BaseUCommerceUrl + 'Apps/Widgets/OrdersByDates/OrdersByDatesView.html',
            controller: ordersByDatesController,
            link: function (scope, elm, attrs) {
    	        scope.elm = elm;
            }
        };
    }
    
    angular.module('ucommerce.directives').directive("ordersByDates", ordersByDates);
    
    

Having "scope: true" in my directive will allow me to access $scope.widget in my controller, which contains properties configured in the container along with user settings like position and size.

Please note that I'm hooking my two new components into the application with the following two lines:

for the controller: angular.module('ucommerce').controller("ordersByDatesController", ordersByDatesController);

for the directive: angular.module('ucommerce.directives').directive("ordersByDates", ordersByDates);

The template file for my directive can be accessed relative easily, by getting the root of the Ucommerce folder using the 'UCommerceClientMgr.BaseUCommerceUrl':

    
    UCommerceClientMgr.BaseUCommerceUrl + 'Apps/Widgets/OrdersByDates/OrdersByDatesView.html'
    

The content of my view is quite simple as visjs will handle most of the rendering.

    
    <div class="height100">
        <h3 class="no-margin">Orders placed per day</h3>
        <div id="ordersByDatesWidget" class="ordersByDatesWidget">
    
        </div>
    </div>
    

Now I just need to fill in the controller that will call my web service, grab the data, and have visjs render the result:

    
    
    	$scope.loadTimeLine = function() {
    
    		$http.get('/ucommerceApi/Widgets/Orders/OrdersByDates/all').then(function (response) {
    
    			var now = new Date();
    			var monthAgo = new Date();
    			monthAgo.setMonth(now.getMonth() - 1);
    
    			var container = $($scope.elm.find('#ordersByDatesWidget')).get(0);
    			var items = response.data;
    			var options = {
    				style: 'bar',
    				barChart: { width: 50, align: 'center' }, // align: left, center, right
    				drawPoints: false,
    				orientation: 'top',
    				autoResize: true,
    				height: '100%',
    				start: $scope.getPrettyDateTime(monthAgo),
    				end: $scope.getPrettyDateTime(now),
    				dataAxis: {
    					left: {
    						range: {
    							min: 0
    						}
    					},
    				}
    			};
    
    			var graph2d = new vis.Graph2d(container, items, options);
    			
    			$timeout(function() {
    				$scope.$emit('loaded');
    			});
    		});
    	}
    
    	$scope.getPrettyDateTime = function(date) {
    
    		var dd = date.getDate();
    		var mm = date.getMonth() + 1; //January is 0!
    		var yyyy = date.getFullYear();
    
    		if (dd < 10) {
    			dd = '0' + dd;
    		}
    
    		if (mm < 10) {
    			mm = '0' + mm;
    		}
    
    		var now = yyyy + '-' + mm + '-' + dd;
    		return now;
    	}
    
    	$scope.loadTimeLine();
    
    

When you're ready to remove the loading symbol on top of your widget, just do an $emit to the parent scope that will remove it for you.

    
    
    $timeout(function() {
    	$scope.$emit('loaded');
    });
    

You can react on a resize event when a user changes the size of your widget. This can be useful if you want to recalculate the size of an element. Just subscribe to the following event in your controller:

    
    
    $scope.$on('widgetsResized',function() {
    	// ... do you stuff here
    });
    
    

Creating the edit view

If your widget has different properties configured under the Properties tag in your configuration, those will be editable OOTB with text boxes where values can be entered by the user. If you want to handle this differently you can configure an edit view that will be visible once in edit mode. Here you will be able to handle each of the properties in any way you want. In the example below, I have a property called 'Interval'as configured by my widget. In this case, I want to handle the property with a select list that has a fixed amount of possible options. The options are defined by the controller in the property 'intervals'. The property will automatically be set by the ng-model so persisting the values will happen automatically for any control where ng-model is supported by AngularJS.

    
    
    <div class="propertyItem" ng-repeat="property in widget.properties | filter:{ 'key':'Interval'}">
        <div class="propertyItemHeader">
    		<span class="widgetPropertyLabel" title="{{property.key}}">{{property.key}}</span>
        </div>
        <div class="propertyItemContent">
    		<select name="singleSelect"
    				ng-options="interval as getTranslatedValue(interval) for interval in intervals track by interval"
    				ng-model="property.value"></select>
    	</div>
    </div>
    	
    

Configuring your widgets

All there's left to do is register your new widget in the container. If you're interested how to do that please read How To Register a Component

Reconfiguring the google analytics widget to show different data.

If you've enabled google analytics widgets on the site, you can leverage the default implementation to show different pieces of data without having to do any code. All you need to do is reconfigure the widget, giving you a new one to configure differently.

Take one of the default ones, place them in your own configuration file and change the following parameters:

Parameter Type Details
Id string New unique id of the new widget so it won't override the default one
Name string New Unique name of your widget.
googleAnalyticsKey string The key for your google analytics API access.
chartType string Google analytics option.
metrics string Google analytics option.
dimensions string Google analytics option.

Please take the time to read Google analytics for valid options to chartType, metrics, and dimensions

Properties can also be edited directly by the user when edit mode is enabled for the widget. Each of the properties will be persisted in the database for that exact widget.