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
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
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
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
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
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