Interacting with Service Catalog Variable Widgets
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-30-2025 02:18 PM
I have a catalog item with a Custom Variable. this custom variable is configured to display a widget on the Catalog Item to collect user information. This widget populates data onLoad of the catalog item and displays the data of users who report to the logged in user.
I've been tasked with updating the behavior of the widget. We would like delegates to be able to use the form, when the typical manager is unable to complete it. The end user should select the proper delegate via a new field on the form and this field should then pass the value to the Wiget, updating it with user information of the users who report to the selected delegate. In other words, if my manager sets me as a delegate. I should be able to open the form. select my manager as the delegating authority, and the widget would load user information of my managers direct reports.
I'm struggling with how to pass a variable value in an onChange format to the server script on the widget. Is this an achievable ask? Do I need a GlideAjax script to achieve this? The server script is as follow's. I was hoping this would be achievable with a simple if statement, looking for a delegate, then pass the value of the delegate selected on the form.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-30-2025 03:07 PM
It's much easier than you think! Given what you have said about "widgets" I assume you're using Service Portal?
Your custom widget can watch for changes to a form with this command in the Client Controller:
$scope.$watch(function() {
return g_form.getDisplayValue("u_course_code");
}, function(value) {
if (value) {
c.data.course_code = g_form.getDisplayValue("u_course_code");
}
});
Make sure to include $scope at the top like this and set g_form:
api.controller = function($scope) {
/* widget controller */
var c = this;
var g_form = $scope.page.g_form;
Your custom widget is able to use g_form to get information from the Catalog Item variables. In this case, we use $scope.$watch to detect changes in the form variable. We then execute a function if there is a change, in my case I am setting a value equal to the new value from the form. You can do whatever you want as a result of the change in form value.
In your case your custom widget will watch for the form value to be changed, then execute code based on that to display the data.
Now if you want to execute a server command here is an example. No judgement on it, I hate formatting dates so I wanted to do it server side as I had all the code worked out for another server script:
Client controller:
$scope.$watch(function() {
return g_form.getDisplayValue("u_proposed_meeting_date_first");
}, function(value) {
if (value) {
c.server.get({
parameter1: value,
action: "get_pretty_date"
}).then(function(response) {
c.data.proposed_date_first = response.data.prettied_date;
});
}
});
Server script:
if (input && input.action == "get_pretty_date") {
var mygd = new GlideDate();
mygd.setDisplayValue(input.parameter1);
var pretty_date = mygd.getByFormat("EEEE") + " " + mygd.getByFormat("MMMMM") + " " + mygd.getByFormat("dd") + ", " + mygd.getByFormat("YYYY");
data.prettied_date = pretty_date;
}
There are always different ways to achieve the same thing so I am sure others will have different methods. Hopefully that gets you started on the right track and you can look to apply it to your problem. Let me know of what questions you have along the way as you get going, but this should get you started in getting a widget to watch for a value change and execute code as a result of that value changing.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-01-2025 07:24 AM
Hey Trevor,
Thanks for the reply! Yes, this is being done on a service portal Catalog item used to perform vendor management tasks....I'm making an assumption that my code changes should be done on the Server script in the widget, as it appears to me that it is building the array of user information there. if there is a simple change I can apply to the client controller, do I still need to feed that value into the server side, so that it knows how to build the array?
I'll list the Client Controller here at the bottom. I'm assuming this new function should go towards the top of the code.
api.controller = function($scope, $rootScope) {
var c = this;
var g_form;
// Pagination stuff
$scope.currentPage = 0;
$scope.rowsPerPage = 25;
$scope.siteSearchFilter = '';
$scope.filteredList = [];
$scope.numberOfPages = function() {
return Math.ceil($scope.filteredList.length / $scope.rowsPerPage);
};
// Sorting stuff
$scope.propertyName = '';
$scope.reverse = false;
$scope.data.sorting = {
'by': $scope.propertyName,
'dir': $scope.reverse ? 'desc' : 'asc'
}
$scope.sortBy = function(propertyName) {
$scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;
$scope.propertyName = propertyName;
$scope.data.sorting = {
'by': $scope.propertyName,
'dir': $scope.reverse ? 'desc' : 'asc'
}
};
$scope.selectrefresh = function(user) {
user.isrefreshed = true;
user.isdeleted = false;
// console.log('User OBJ 1 : ' + JSON.stringify(c.data.users));
$scope.page.g_form.setValue('vendor_user_information', JSON.stringify(c.data.users));
}
$scope.deselectrefresh = function(user) {
user.isrefreshed = false;
$scope.page.g_form.setValue('vendor_user_information', JSON.stringify(c.data.users));
// console.log('User OBJ 2 : ' + JSON.stringify(c.data.users));
}
$scope.selectdelete = function(user) {
user.isdeleted = true;
user.isrefreshed = false;
// console.log('User OBJ 3 : ' + JSON.stringify(c.data.users));
$scope.page.g_form.setValue('vendor_user_information', JSON.stringify(c.data.users));
}
$scope.deselectdelete = function(user) {
user.isdeleted = false;
// console.log('User OBJ 4 : ' + JSON.stringify(c.data.users));
$scope.page.g_form.setValue('vendor_user_information', JSON.stringify(c.data.users));
}
};
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-01-2025 08:42 AM
@Nick78 wrote:I'm making an assumption that my code changes should be done on the Server script in the widget, as it appears to me that it is building the array of user information there.
As far as I can tell from your requirements you need code changed in both the Client Controller and Server Script:
a) Client Controller: This is where you will watch for the change on the Catalog Item variable. This is where you add the $scope.$watch function. Think of this as your "onChange".
b) Server Script: This is where you will perform the server side code like your user lookup. This needs to change because you want to pass in the Catalog Item variable value now. This is the function that $scope.$watch will call in the c.server.get. Think of this as the code that exists "onChange".
@Nick78 wrote:if there is a simple change I can apply to the client controller, do I still need to feed that value into the server side, so that it knows how to build the array?
Correct, you will make a change to the Client Controller to watch for the value being changed. When the value is changed you will then call the function in the Server Script. This is the second example I posted which has c.server.get that calls a function on the server side, passes a value, and then accepts a value in return.
@Nick78 wrote:I'll list the Client Controller here at the bottom. I'm assuming this new function should go towards the top of the code.
The $scope.$watch function can go anywhere within the Client Controller, it doesn't need to go at the top.
I declare $scope.page.g_form as the variable g_form because it saves me from typing it over and over again. That part you don't need if you don't want to use it, you'll just need to type $scope.page.g_form everywhere I type g_form.
Let me know if I can help more!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-01-2025 09:53 AM - edited 05-01-2025 09:54 AM
ok, so I've made some changes but, I'm not seeing any results.
Updated Server Script:
(function() {
/* populate the 'data' object */
/* e.g., data.table = $sp.getValue('table'); */
if (input && input.action == 'get_delegate') {
var manager;
manager.setDisplayValue(input.parameter1);
data.delegate = manager;
var getUsers = new GlideRecord('sys_user');
// getUsers.addEncodedQuery('managerDYNAMIC90d1921e5f510100a9ad2572f2b477fe^active=true^employee_number=NULL');
getUsers.addQuery('manager', manager);
getUsers.addActiveQuery();
getUsers.addEncodedQuery('sourceLIKE-Vendor');
// getUsers.addEncodedQuery('employee_number=NULL');
getUsers.query();
var usersArray = [];
var i = 1;
while (getUsers.next()) {
var userObj = {};
userObj.id = i;
userObj.user_id = getUsers.user_name.toString();
userObj.user_name = getUsers.name.toString();
userObj.company = getUsers.company.name.toString();
userObj.facility = getUsers.location.name.toString();
userObj.manager = getUsers.manager.name.toString();
userObj.domain_account_expiration = getUsers.u_account_expiration_date.toString();
userObj.isrefreshed = false;
userObj.isdeleted = false;
usersArray.push(userObj);
i++;
}
data.users = usersArray;
}
})();
Updated Client Controler:
$scope.$watch(function() {
return $scope.page.g_form.getDisplayValue("delegate");
}, function(value) {
if (value) {
c.server.get({
parameter1: value,
action: "get_delegate"
}).then(function(response) {
c.data.delegate = response.data.delegate;
});
}
});
I suspect the problem I'm running into now is on the server side in translating the 'manager' into the correct format. But do have a question on your client controller example. In the following line, does "proposed_date_first" reference back to any value on a form or elsewhere?
c.data.proposed_date_first = response.data.prettied_date;