Hiding a UI Action button from server-side code (e.g. Business Rule)?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-10-2014 03:40 PM
I've got a cool UI Action button called "Schedule Appointment" and I have client scripts which go in onLoad of the form and onChange of a specific value either hide or show the button (using style.display). It uses jQuery code to do this. All of that works fine, however for conditions that should NOT show the button, in practice: for 0.5 seconds the button appears on the screen (since it doesn't have a condition) and then drops off of the screen when the onLoad client script "hides" it due to the condition not being met. I am looking at how to resolve hiding the "Schedule Appointment" faster so that it doesn't "lag" and show the button for even a brief period of time. I think that a "display" Business Rule would be where to do this, but I cannot seem to be able to reference a button on the screen: both jQuery and javascript do not work for being able to grab the button as far as I can tell, I'm guessing because its running server-side. Below is what I've tried.
Business Rule Name: Appointment Scheduling OnLoad functions
Table: incident
Active: true
Advanced: true
When: display
Order: 100
jQuery method Script:
onDisplay(); function onDisplay() { if(doesButtonExist('u_schedule_appointment') && getButtonDisplay('u_schedule_appointment') != 'none') { //Check for non-Appointment types if (current.u_category.u_type != 'appointment') { //Hide the 'Schedule Appointment' button setButtonDisplay('u_schedule_appointment','none'); } else { //Show the 'Schedule Appointment' button setButtonDisplay('u_schedule_appointment','inline'); } } var grAppt = new GlideRecord('u_appointment'); grAppt.addQuery('u_appointment_task', g_form.getUniqueValue()); grAppt.addQuery('u_appointment_state', 'Scheduled'); grAppt.query(); if (gr.next()) { //While the recordset contains records, iterate through them g_form.addInfoMessage('<span style="background-color: yellow; font-weight: 900;">An appointment has been scheduled for this incident.</span>'); } } // Valid styles: block, none, inline function setButtonDisplay(button_name,display_style) { var items = $$('BUTTON').each(function(item){ if(item.id == button_name){ item.style.display = display_style; } }); return true; } function getButtonDisplay(button_name) { var items = $$('BUTTON').each(function(item){ if(item.id == button_name){ return item.style.display; } }); return null; } function doesButtonExist(button_name) { var counter = 0; var items = $$('BUTTON').each(function(item){ if(item.id == button_name){ counter++; } }); if (counter == 0) { return false; } else { return true; } }
jQuery method brings up the message "$$ is not defined" in the call stack. It breaks on onDisplay() -> doesButtonExist() -> line 47.
javascript method Script:
onDisplay(); function onDisplay() { if(doesButtonExist('u_schedule_appointment') && getButtonDisplay('u_schedule_appointment') != 'none') { //Check for non-Appointment types if (current.u_category.u_type != 'appointment') { //Hide the 'Schedule Appointment' button setButtonDisplay('u_schedule_appointment','none'); } else { //Show the 'Schedule Appointment' button setButtonDisplay('u_schedule_appointment','inline'); } } var grAppt = new GlideRecord('u_appointment'); grAppt.addQuery('u_appointment_task', g_form.getUniqueValue()); grAppt.addQuery('u_appointment_state', 'Scheduled'); grAppt.query(); if (gr.next()) { //While the recordset contains records, iterate through them g_form.addInfoMessage('<span style="background-color: yellow; font-weight: 900;">An appointment has been scheduled for this incident.</span>'); } } // Valid styles: block, none, inline function setButtonDisplay(button_name,display_style) { var refs = document.getElementsByTagName("BUTTON"); if (refs) { for (var i=0; i < refs.length; i++) { var teststr = refs[i].innerHTML.toString(); if (teststr.match(button_name)) { refs[i].style.display = display_style; } } } return true; } function getButtonDisplay(button_name) { var refs = document.getElementsByTagName("BUTTON"); if (refs) { for (var i=0; i < refs.length; i++) { var teststr = refs[i].innerHTML.toString(); if (teststr.match(button_name)) { return refs[i].style.display; } } } return null; } function doesButtonExist(button_name) { var counter = 0; var refs = document.getElementsByTagName("BUTTON"); if (refs) { for (var i=0; i < refs.length; i++) { var teststr = refs[i].innerHTML.toString(); if (teststr.match(button_name)) { counter++; } } } if (counter == 0) { return false; } else { return true; } }
javascript method brings up the message "document is not defined" in the call stack. It breaks on onDisplay() -> doesButtonExist() -> line 54.
Is there any way to reference the UI Action's button at this point, or is there another method to hide the button earlier "onLoad"? Or is it just not possible to reference a UI Action button using a Business Rule?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-10-2014 06:24 PM
You are correct, your client-side code will not run within a Business Rule, even an onDisplay one - the Business Rule knows nothing about the client-side button.
What about changing the button to a Related Links link action instead (Form link)? I know it may not be the best solution, but you can barely, if at all, see it disappear on form load?
And just to clarify, out of the box, ServiceNow uses the Prototype JavaScript library and not jQuery (both use the $ and $$ shortcuts).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-11-2014 09:09 AM
I was afraid that that was the case. In other frameworks I've worked in (.NET, etc.), usually I can at least hook into the pipeline server-side just after page-rendering to modify elements (usually presented as objects) on the page.
I'll ask our team about the Related Links, as I'm sure the "lag" won't be as visible there, but we chose a button in order for it to be extremely visible on the page, since for Appointment type classifications they need to Schedule an appointment. For training, it's easier for our Service Desk to find it as a button than under Related Links.
Since Client Scripts don't have an "Order" per se, I've modified the Client Script to run first by naming it "01a[script name]". It's reduced the lag a bit, but its still visible for a short period of time. I'll try running it from UI Policy to see if that reduces the lag.
Thanks for letting me know about that its using the Prototype library instead of jQuery -- they both looked very similar to me. I'll be sure to review the Prototype documentation instead.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-10-2014 06:38 PM
business rule can't do it since button is client side...
but why cant you make use of condition field of ui action to hide/display the button?
I am assuming that you are checking if some particular record exists or not before hiding or showing the button... Why can't you try this?
use condition field as
javascript: new anyscriptinclude().function()
have your code of validation in the script include and return true or false to show/hide the button ? does that help ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-11-2014 08:56 AM
Putting something in the UI Action condition field doesn't work for our processes.
This is because the button visibility is based on a Reference field's type (e.g. "Classification.Type") and the Reference field is modifiable by the user. If that UI Action condition is "false", it will completely remove the button off of the page On Load -- however, once that Reference field is changed, there is no way to bring that button back onChange of the Reference field if the Type matches our condition value, because no button is rendered on the page -- it doesn't "hide" it via a display value, it decides whether to render the button or not depending on the values on the page server-side. The only way to make the button visibility truly responsive is to remove all UI Action conditions and run the conditions on the client-side (using a Client Script or UI Policy), which is what I am doing now (using Client Script).