A common feature request for Service Portal is to be able to add custom buttons to the sc_request or ticket page similar to the way you could add UI actions to a form. This functionality is not available out-of-box, but here is a quick example on how you could create a custom widget to display some buttons to mimic the UI Actions on a form.
In this example, we will create a “Resolve Incident” button to place on the incident “ticket” page.
HTML:
1 2 3 4 5 6 7 | <div class="panel panel-default"> <div class="panel-heading">Actions</div> <div class="panel-body"> <button type="button" class="btn btn-primary btn-block" ng-click="c.uiAction('resolve')">Resolve Incident</button> <button type="button" class="btn btn-default btn-block" ng-click="c.uiAction('cancel')">Cancel</button> </div> </div> |
Client Script:
1 2 3 4 5 6 7 8 9 | function() { var c = this; c.uiAction = function(action) { c.data.action = action; c.server.update().then(function() { c.data.action = undefined; }) } } |
Server Script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | (function() { // Get table & sys_id data.table = input.table || $sp.getParameter("table"); data.sys_id = input.sys_id || $sp.getParameter("sys_id"); // Valid GlideRecord gr = new GlideRecord(data.table); if (!gr.isValid()) return; // Valid sys_id if (!gr.get(data.sys_id)) return; if (input && input.action) { var action = input.action; // If Incident table if (data.table == 'incident') { if (action == 'resolve') { // Resolve Incident gr.setValue('incident_state', 6); gr.setValue('state', 6); gr.setValue('resolved_by', gs.getUserID()); gr.update(); } if (action == 'cancel') { // Do something else } } } })(); |
The resulting widget should look something like this:
This is far from the complete solution, but will hopefully provide a good example to work off of.
Hi Nathan,
Thanks for this – it has helped a lot.
Regarding the if action = resolved code block, what is the best way to address having a pop up box to confirm that you want to resolve the incident?
I have tried the following, however I get an error when clicking the button
// If Incident table
if (data.table == ‘incident’) {
if (action == ‘resolve’) {
if(confirm(“Are you sure you want to Resolve this Incident?”)){
// Resolve Incident
gr.setValue(‘incident_state’, 6);
gr.setValue(‘state’, 6);
gr.setValue(‘resolved_by’, gs.getUserID());
gr.update();
}
//If cancel abort
return false;
}
The Error I receive is: Server JavaScript error “confirm” is not defined.
Looking at that error – would I need to define confirm in the client script? If so – I am not too sure what to add?
Cheers Nathan, just stumbled upon the blog and really liking it.
Cheers,
Brendan
Hi Brendan, that’s because “confirm” is a client side method that is run in the browser so it’s not possible to execute from server script.
Brendan,
Add something like this to your Client Script
function() {
var c = this;
c.uiAction = function(action) {
if(action == ‘cancel’){
var r = confirm(“Are you sure you want to cancel this request?”);
if(r == false){
return;
}
}
c.data.action = action;
c.server.update().then(function() {
c.data.action = undefined;
})
}
}
Awesome post,thanks
Yes, must be client side:
c.uiAction = function(action) {
if(!confirm(“Are you sure?”)) return;
c.data.action = action;
c.server.update().then(function() {
c.data.action = undefined;
})
}
Thanks Nathan, that worked 🙂
Thanks Nathan – this worked like a champ!
Is there an easy way to make the buttons a specific color? As is the top button gets the same color as the top heading of the other widgets on the page. I’m sure it is just using the default style, but I don’t know where or how to override that.
Hi Jeff,
The button colors is getting the color from the “btn-primary” Bootstrap class which gets compiled based on the CSS variables you have defined. You can always change out the class for one of the other color classes (e.g. btn-success, btn-info) or create a custom class and style it in the CSS field on the widget. If you need help, shoot me an email and I can show you an example.
Hi Nathan, thanks for the post, very handy indeed.
I wanted to ask you what the difference is between using server.update() and server.get()? So for example, your code block in the controller would be something like:
c.uiAction = function(action) {
c.server.get({
action: action
}).then(function(response) {
/…… /
});
};
I’m trying to find any information on the difference, thanks again.
Hi Nathan,
I just replicated the code in my portal .
The server update is not getting done i.e, the particular incident is not getting resolved , even though gs.info is getting logged in log statement.
if(data.table == ‘incident’){
if(action ==’resolve’){
gs.info(‘inside resolve’ +action);
//gr.setValue(‘incident_state’,6);
gr.setValue(‘state’,6);
Not able to understand what is the mistake i am doing
Hi Nathan,
Thanks for this – it’s great!
I’m just wondering if there’s any way I can get it to only show if the state isn’t resolved or closed etc?
Also, it would be great if it could update the Work Notes or Additional comments that the user has resolved it!
Thanks
Mithun
This is just to be an example and up to you to finish. You can use ng-if on the button to hide when state not resolved. You can also easily add to the worknotes from the server script.
Hi Mithun,
I used the code above to create a ‘Reopen Incident’ button and have it show only if the state is resolved. I added ng-if=”data.showButton” to the HTML template.
In the Server Script…
if(data.table == ‘incident’ && gr.state == 6){
data.showButton = true;
} else {
data.showButton = false;
}
Seems to be working well.
Hi, can you post the code you used for this? I’m trying to do the same thing and made some edits, but I’m still having a bit of trouble.
Hi Troy,
Thanks for your code it works well in my implementation – just a note that might be handy, I worked with one of our web developers and he shortened this down to a single line which works really well, figured I’d share:
data.showButton = gr.state == 6;
Cheers
Carl.
I have a requirement to create close button . i used ng-hide to hide button when state closed but when i reload the form “Close” button again appearing . plz suggest a way if state is closed button is not visible
That just means the expression in your ng-hide is not returning true. Double check the values and make sure they are correct and of the correct type. For example, sometimes what you think is a Boolean could be a String. But without seeing your code I cannot comment further.
https://community.servicenow.com/message/1079189#1079189
here is my code in last you can check it and let me know any mistake or wrong code
Hi Ankit,
Did you figure this out? I have the same issue when reloading the form the button re-appears.
Hi Nathan,
I want a button which should send comments to the back end table. For example an approval widget I have created a comment text box and send button. When user wants any additional info user will add information in the comment field and hit on send button. then comments should passed to the approval form. Can you please help me on this.
Thanks,
DGP
The concepts in this tutorial would work just the same for this use case… create a button, capture the info and send to the server using server.update, and then use GlideRecord to insert the data to the appropriate table.
Hi Nathan,
Thanks for code! Works slick. I created a ‘Reopen Incident’ button and was able to hide it if the inc state isn’t resolved. However, I need to require comments if they try to reopen the incident. I can’t seem figure out the code to look at the comments box and stop the reopening if there isn’t a comment.
I’ve discovered g_form doesn’t work like it does on the ‘Reopen Incident’ in the incident form in the native view. Any help would be appreciated! Thanks.
I expanded upon Nathan’s ideas and added a modal window for resolve comments and a few improvements.
http://www.servicenowelite.com/blog/2017/5/12/service-portal-resolve-incident-button
Thanks Nathan, this site helped me out a lot.
Thanks Mike,
That’s a great addition. Thanks for sharing!
Hello Mike,
I’m trying to use the widget code that is in the following link, http://www.servicenowelite.com/blog/2017/5/12/service-portal-resolve-incident-button, but is not working.
It doesn’t show the Widget at all when using the first line and the Client Controller script is giving error “It should contain a javascript function” when saving the same exact code.
Can anyone please advise?
Hi Troy,
This is exactly what I intend to do.
Can you let me know how you implemented hiding the button when state is not resolved, I am new to Service Portal and hence I am asking this noob question
Thanks,
Urmilla
How do you add that button to the form?
Just drag it to the page using the designer.
What if I have a form widget and a custom button widget on same page. If I change any value to the form and click on button, it updates the form.
What I m trying to achieve is to redirect on button click as well as save the form. As you know action.setRedirectURL() does not work with Service Portal, so I achieved it by changing some part of your code. But I am still trying to figure out how to update the form.
Any views?
You could update the form widget to submit upon an event, and then trigger the event from your button widget.
See here: https://serviceportal.io/using-events-communicate-widgets/
Hi Nathan,
Thanks for the reply.
Is there any way I can call the out of the box event in form widget to update the record? I see below set of code which updates the form onclick of UI Action.
$scope.$on(“spModel.uiActionComplete”, function(evt, response) {
var sysID = (response.isInsert) ? response.sys_id : $scope.data.sys_id;
loadForm($scope.data.table, sysID).then(constructResponseHandler(response));
});
My button widget has a glide object of the same table and record as the form, but when I try to pass it, it is still not updating the form. If I don’t pass any response it gives me a console error.
$rootScope.$broadcast(“spModel.uiActionComplete”, c.data.gr);
c.data.gr has the glide object from server script.
data.table = input.table || $sp.getParameter(“table”);
data.sys_id = input.sys_id || $sp.getParameter(“sys_id”);
data.id = input.id || $sp.getParameter(“id”);
// Valid GlideRecord
var gr = new GlideRecord(data.table);
if (!gr.isValid())
return;
// Valid sys_id
if (!gr.get(data.sys_id))
return;
data.gr = gr;
I also tried by getting the “g_form” broadcast from form widget to button widget and resend it back as the response. Still no luck.
Thanks
Karan
Hi Nathan,
Hope this will show what I was trying to achieve, thanks for help buddy!!
https://community.servicenow.com/thread/277347
Thanks
Karan
HI All,
How to add a button as”modify Approver?”(should refer to User table) in the catalog item form . Once added approver it should get reflected in the respect form.
THanks
Hi Nathan
I have my html set to show / hide certain buttons:
<button ng-if="data.state!=130 && data.state!=3"
However, once I click the resolve button, the incident will resolve, my comments added etc, but the resolve button does not disappear until I refresh my browser..
Any ideas?
Thanks
can we make a field mandatory while using the Resolve Button
How to hide custom button based RITM state. I want to hide button if the ritm is approved.
if the stage is waiting for approval, button should be visible
I created a button for cancel on the service portal using this site thank you it was so useful! I now tried to created a request approval button on the service portal which works exactly as i need it to, however the button visibilty should only show when on the change_request ticket form and seems to be coming up on incident as well, so i think I’m missing something because its not reading my visibility code. Also when i click request approval the button is not disappearing?
Thanks for posting this – really useful.
I’m trying to add a button to update a field in the HR Module (table=sn_hr_core_case) but when I reload my page where I have added the widget I receive a bunch of read errors at the top whic are:
-Server Javascript error Cannot read property “table” from undefined
-Line number 4
-Script source code logged to browser console
-failing widget: ‘Opus Reapproval’ (sys_id of my widget)
Not sure why this isn’t working – is it because I’m in the ‘HR Service Portal’ scope?
I have this working now – I made it more HR Case specific as opposed to a generic ‘table’ property.
Hi,
Worked with one of our internal web developers and he shortened the section int he server script, lines 16 to 32:
if (input && input.action) {
var action = input.action;
// If Incident table
if (data.table == ‘incident’) {
if (action == ‘resolve’) {
// Resolve Incident
gr.setValue(‘incident_state’, 6);
gr.setValue(‘state’, 6);
gr.setValue(‘resolved_by’, gs.getUserID());
gr.update();
}
if (action == ‘cancel’) {
// Do something else
}
}
}
The new code looks like this:
switch (input && input.action) {
case ‘resolve’:
gr.setValue(‘incident_state’, 6);
gr.update();
break;
// case ‘cancel’:
//do something else – keep adding case sections for more buttons…
}
Quite a lot shorter, hope this helps someone.
Cheers
Carl.
Nathan this is great! how would i make it greyed out once clicked?
You can use the ng-disabled=”shouldBeDisabled” directive in the button and decide when to make it true or false in you client controller
Very Simple, Robust, understandable and opens up the mind to more complex use cases on buttons in portal.
Thanks a lot
Great article Nathan – many thanks.
Can you give any advice regarding either re-sizing the button text according to size of the button, or preferably wrapping the button text if the button is too narrow to accommodate the text (at present the text will extend outside the button if the button width is too small).
thanks again
I want code hmtl and server and client script for creating registration form can anyone help me. Do it plz
so what is the final code for HTML, Client Controller, and Server Script. Not sure I can follow all the chats. Can someone just add the final code for all? I am only looking to add a Reopen Incident button.
Simply take the code from the post and change lines 24-26 to open the incident instead of resolving it.
Hello ,
I need the update button in the service portal for the incident table.
When i click the update button then all the data inthe form form should update in the service portal.
Can u please help for html,css, client,server code on widget.
I am creating one button in my widget once user can click that button I need to update selected incident record comments
I have to get Accept and reject buttons when incident was resolved. Can you please help
Hello All,
I have implemented the code in my MSP Instance for one of our customer.But no luck,The code is not working as expected.Even when I click on Resolve Button its not working nor its resolving the Incident.
Can anyone help me out here.
Thanks
I want to make additional comments mandatory whenever user clicks resolve incident button
This does allow setMandatory, but its a great way to do small client side stuff. I have found a way however to enable client side scripting on all ui actions, this also works without modifying the OOTB form widget. The method is described in the Article:
https://community.servicenow.com/community?id=community_article&sys_id=b1588f6fdbcf011439445ac2ca961922
Hi,
How to use the ui action in widge in portal
Thanks
how to create save and cancel buttons when changes are made in popup on serviceportal
Hi,
Can I know how to create a custom button to create a new incident on portal ?
Hi,
Can we copy a existing RITM from portal to create new and user should be able to modify and submit new RITM from Portal page.
Hi Nathan,
I have one requirement , create “copy” button , on-click copies entire form and redirect to duplicate form along with the which we have filled values in variables on record producer form in service portal. Could you please help me on this
These action should works before submit the form. Post creation of other form user would submit the both forms individually if required