Blog

Using Widgets in Catalog Items

Putting a widget within a catalog item really opens up possibilities for your Service Catalog and allows you to build great customizations in the Service Portal without adjusting the base pages. It is also helpful in building new variable types that don’t currently exist.

Here are some examples that you can use in your catalog items.

Example: Price

Code

Variable
Question: Price
Name: price
Type: Macro with Label
Widget: Variable Currency

Result

Capture1.PNG

Example: PERCENTAGE

Code

Variable
Question: Percentage
Name: percentage
Type: Macro with Label
Widget: Variable Percentage

Result

Example: SSN

Note: This one produces an error when not using the hrprofile table. So I cloned the Variable SSN Widget and removed the Server Script that pulls from hr_profile

Code

Variable
Question: SSN
Name: ssn
Type: Macro with Label
Widget: Variable SSN v2
Widget
Clone Variable SSN and remove server script

Result

Capture3.PNG

Example: Number

In this example, you may want to adjust the “max number” in the widget. However I left it in there in case you like it.

Code

Variable
Question: Number
Name: number
Type: Macro with Label
Widget: Variable Number
Widget
HTML

<div class="row">
  <div class="col-md-2">
      <input ng-model="page.fieldValue" ng-model-options="{getterSetter: true}" class="form-control number">
  </div>
  
  <div class="col-md-10">
    <div ng-if="error" class="alert alert-danger" role="alert">${Has to be a number}</div>
    <div ng-if="warn_value" class="alert alert-warning" role="alert">${Enter a value from 0 to 100000}</div>
  </div>
</div>

CSS

(function() {
  /* populate the 'data' object */
  /* e.g., data.table = $sp.getValue('table'); */

})();

Client Controller

function ($scope) {

	$scope.$watch('page.field.value', function(nv, ov) {
		$scope.error = false;
		$scope.warn_value = false;
		if (!nv)
			return; 

		$scope.error = isNaN($scope.page.field.value);
		if ($scope.error)
			return; 
		
		var t = parseFloat($scope.page.field.value);
		if (t < 0 || t >1000000)
			$scope.warn_value = true;
	})
}

Result

Capture5.PNG

Example: Phone Number

In this example, I reworked the Variable SSN Widget mentioned earlier to make a phone number widget.

Code

Variable
Question: Phone Number
Name: phone_number
Type: Macro with Label
Widget: Variable Phone Number

Widget

HTML

<div>
  <input type="text" ng-model="phone.area" class="phone area form-control input-group" maxlength="3" placeholder="XXX" /><span class="color-gray padding-left-and-right-five-px">-</span>
  <input type="text" ng-model="phone.prefix" class="phone prefix form-control input-group" maxlength="3" placeholder="XXX" /><span class="color-gray padding-left-and-right-five-px">-</span>
  <input type="text" ng-model="phone.line" class="phone line form-control input-group" maxlength="4" placeholder="XXXX" />
</div>

CSS

.phone {
  display: inline;
}

.phone.area {
  width: 4em;
}

.phone.prefix {
  width: 4em;
}

.phone.line {
  width: 5em;
}

Server Script

var gr = GlideRecord('sys_user');
gr.addQuery('user', gs.getUserID());
gr.query();
if (gr.next()) 
	data.phone = gr.phone+"";


Client Controller

function ($scope) {
	var phone = $scope.data.phone;
	var phone_area = '';
	var phone_prefix = '';
	var phone_line = '';
	var phoneAreaLen = 3;
	var phonePrefixLen = 2;
	var phoneLineLen = 4;
	if(phone){
		phone_area = phone.substr(0,phoneAreaLen);
		phone_prefix = phone.substr(phoneAreaLen,phonePrefixLen);
		phone_line = phone.substr(phone.length - ssnLineLen);
	}
	$scope.phone = {
		area: phone_area,
		prefix: phone_prefix,
		line: phone_line
	};

	$scope.$watch('phone.area', watch);
	$scope.$watch('phone.prefix', watch);
	$scope.$watch('phone.line', watch);
	function watch(nv, ov) {
		var p = $scope.phone;
		// needs validation
		$scope.page.field.value = p.area + p.prefix + p.line;
	}
}

Result

Capture4.PNG

Example: Display TEXT

This is one of the most helpful, yet simple widgets. Display some text on the form, just have to add the text to the instructions part of the variable.

Code

Variable
Question: Display Text
Name: display_text
Type: Macro
Widget: Variable Text
Instructions: Hello world. Or your text!
Widget: Variable Text
HTML

<div ng-bind-html="c.data.instructions"></div>

Client Controller

function($scope) {
	var c = this;
	var message = '';
	var g_form = $scope.page.g_form;
	var field = $scope.page.field;
	var fieldSysId = field.sys_id.toString();
	var grItem = new GlideRecord('item_option_new');
	grItem.addQuery('sys_id', fieldSysId);
	grItem.query(varInfo);
	function varInfo(grItem) {
		if (grItem.next()) {	
			c.data.instructions = grItem.getValue('instructions').toString();
		}
	}
}

ACLs

Here are some access controls to open up the instructions field so that a user can see the text. You can be more limiting with your access controls of course.

Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.*
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.instructions

Result

Capture6.PNG

Example: Display Section

Code

Variable
Question: Display Section
Name: display_section
Type: Macro
Widget: Variable Section
Instructions: Hello world. Or your text!
Widget: Variable Text
HTML

<div style="padding: 5px 0px 1px 10px; background:#30B5A0;border-radius: 3px;color:white;" ng-bind-html="c.data.instructions"></div>

Client Controller

function($scope) {
	var c = this;
	var message = '';
	var g_form = $scope.page.g_form;
	var field = $scope.page.field;
	var fieldSysId = field.sys_id.toString();
	var grItem = new GlideRecord('item_option_new');
	grItem.addQuery('sys_id', fieldSysId);
	grItem.query(varInfo);
	function varInfo(grItem) {
		if (grItem.next()) {	
			c.data.instructions = grItem.getValue('instructions').toString();
		}
	}
}

ACLs

Here are some access controls to open up the instructions field so that a user can see the text. You can be more limiting with your access controls of course.

Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.*
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.instructions

Result


Example: Display Image

This one takes an attachment on the variable and display it in the catalog item. Very helpful!

Code

Variable
Question: Display Image
Name: display_image
Type: Macro
Widget: Variable Image
Attached: Image
Widget: Variable Text
HTML

<h5></h5>
<p><img style="align: baseline;" title="" ng-src="" alt="" width="100%" height="100%" align="bottom" border="0" hspace="-1" vspace="0" /></p>

Server Script

(function() {
	var catItemID = $sp.getParameter("sys_id");
})();

Client Controller

function($scope) {
	
	var c = this;
	var message = '';
	var g_form = $scope.page.g_form;
	var field = $scope.page.field;
	var fieldSysId = field.sys_id.toString()
	
	//Get Attachment Image Name
	var grAttachment = new GlideRecord('sys_attachment');
	grAttachment.addQuery('table_name', 'item_option_new');
	grAttachment.addQuery('table_sys_id', fieldSysId);
	grAttachment.query(attachInfo);
	function attachInfo(grAttachment) {
		if (grAttachment.next()) {	
			c.data.image = 'sys_attachment.do?sys_id='+grAttachment.sys_id;
		}
	}
	
	//Get Question Text	
	var grItem = new GlideRecord('item_option_new');
	grItem.addQuery('sys_id', fieldSysId);
	grItem.query(varInfo);
	function varInfo(grItem) {
		//alert('grItem Query: ' + grItem.getEncodedQuery() + ' = ' + grItem.getRowCount());
		if (grItem.next()) {	
			c.data.title = grItem.question_text.toString();
		}
	}
}


ACLs

Here are some access controls to open up the instructions field so that a user can see the image. You can be more limiting with your access controls of course.

Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.*
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.
Type: record, Operation: read, Admin Overrides: true
Name: item_option_new.instructions

Result

Capture9.PNG