- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-20-2016 07:38 AM
I have a requirement to create a new record from an existing record, similiar to how Incident has a "create problem" button. The problem is that with the "Create Problem" button, just clicking on the button creates the record.
What I would like to do instead is redirect a user to a new form, with the fields pre-populated based on what was in the previous record. I've been trying to figure out how to do this with a UI Action and setting the URI sysparm to current.{field} but I can't get it to work. Has anyone done something similar and can point me in the right direction?
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-27-2016 08:23 AM
So the above suggestions didn't actually work, and this entire thing turned out to be far more complicated than I originally thought. I've outlined the requirement and the steps I took to meet it below in-case anyone else runs into a similar issue.
Requirement:
Open a new record from a form associated to the record the form button is clicked from. Instead of submitting a record and redirecting, open to a new form with the data pre-populated. This is all to be done within a scoped app.
Issues with URI
Using a URI as a redirect to a new form does not work. You can use it to direct to an existing form record and populate some of the data, but if you are going to a brand new form with no record submitted it won't work properly. However you attempt to do it, Service Now will treat it as though you are loading an external URL and re-load the entire frame within the existing frame. Ironically, it does fill the data out, but you're left with a frame within a frame until you reload the URL.
I tried this using window.location, manually entering the URI into the gsft_main panel as above, and doing it server side with setRedirect and setRedirectURL. Every time I got it to redirect this was the behavior, so I decided to try to use GlideDialog to direct to a UI page containing a form to insert a record to the table.
Issues with GlideDialog
GlideDialog was promising, however it seems to be bugged for scoped apps. While there's a GlideDialog scoped API, the render() function seems to be dependent on a non-scoped API. Each time I would build the form and render it I would end up with an error stating an API was not in scope. I don't have it written in my notes, but I believe it was GlideMobileOrDesktop, or something like that. I believe it was trying to determine what type of device I was on in order to render the frame. This error would stop the UI Page client script from running, so the form would open but you would be unable to submit it.
Solution
I was ultimately able to fix this by using a client UI Action, a GlideAjax script, and the GlideDialogForm function. My UI Action grabs the sys_id of the form you're on and sends it to the GlideAjax, which runs a GlideQuery and pulls in the information I need. It then builds the data into an XML file and sends it back to the UI Action (standard GlideAjax stuff). From there I parse the XML and use g_form to write to the fields before rendering the dialog box. The box takes a couple seconds to load after clicking it, but it's fine for us since this a feature we don't expect people to be using very often. I've included my code below in case anybody is running into a similar issue. As a final note, we are currently running on Fuji.
UI Action
function setRedirection(){
//Call GlideAjax and parse XML response into local variables
var gajax = new GlideAjax('taskAjax');
gajax.addParam('sysparm_name', 'getIntakeValues');
gajax.addParam('sysparm_sys_id', g_form.getUniqueValue());
gajax.getXML(getResponse);
//Parse XML and write to form
function getResponse(response){
//Create Dialog form and add -1 to direct to new form
var dialog = new GlideDialogForm('Manual Task','scoped table');
dialog.setSysID(-1);
//Create callback for Dialog and load frame
dialog.setLoadCallback(function(iframeDoc) {
// To get the iframe: document.defaultView in non-IE, document.parentWindow in IE
var dialogFrame = 'defaultView' in iframeDoc ? iframeDoc.defaultView : iframeDoc.parentWindow;
dialogFrame.g_form.setValue('application',(response.responseXML.getElementsByTagName("application")[0].getAttribute('value')));
dialogFrame.g_form.setValue('request_type',(response.responseXML.getElementsByTagName("request_type")[0].getAttribute('value')));
dialogFrame.g_form.setValue('sub_type',(response.responseXML.getElementsByTagName("sub_type")[0].getAttribute('value')));
dialogFrame = null;
});
dialog.render();
}
}
GlideAjax
var taskAjax= Class.create();
dcoeManualTaskAjax.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
ajaxFunction_getIntakeValues : function(){
//Grabbing sys_id from client script
var sysID = this.getParameter('sysparm_sys_id');
//Calling private function to run glideQuery and save Intake values
this._query(sysID);
//Setting "result" message on XML
var result = this.newItem("Result");
result.setAttribute("message","returning intake values for " + this.number);
//Calling private function to build intake values into XML
this._setXMLValues("application",this.application);
this._setXMLValues("request_type",this.request_type);
this._setXMLValues("sub_type",this.sub_type);
},
_setXMLValues: function(name, value){
var setValue = this.newItem(name);
setValue.setAttribute('value',value);
},
_query: function(sysID){
var gr = new GlideRecord("x_mce_dcoe_intake_x_mce_dcoe_intakes");
gr.addQuery('sys_id',sysID);
gr.query();
while(gr.next()){
this.number = gr.number;
this.application = gr.application;
this.request_type = gr.request_type;
}
},
type: 'taskAjax'
});

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-20-2016 07:59 AM
In that case I would just redirect the user to the service request record and prepopulate the fields by doing a client side url redirect. This article describes how to set those values:
http://wiki.servicenow.com/?title=Navigating_by_URL
Make sure you're doing this in a client side ui action rather than the standard server side action.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-20-2016 08:07 AM
You could actually do this server side as well with:
var url = 'url to prepopulate values';
action.setRedirectURL(url);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-20-2016 08:21 AM
Thank you, this definitely pointed me in the right direction. We're currently configuring a client UI action to use g_form to grab the values from the form, and getTopWindow().NavPageManager.get().getPane('gsft_main').loadLinkFromUrl(url); to set the redirect.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-27-2016 08:23 AM
So the above suggestions didn't actually work, and this entire thing turned out to be far more complicated than I originally thought. I've outlined the requirement and the steps I took to meet it below in-case anyone else runs into a similar issue.
Requirement:
Open a new record from a form associated to the record the form button is clicked from. Instead of submitting a record and redirecting, open to a new form with the data pre-populated. This is all to be done within a scoped app.
Issues with URI
Using a URI as a redirect to a new form does not work. You can use it to direct to an existing form record and populate some of the data, but if you are going to a brand new form with no record submitted it won't work properly. However you attempt to do it, Service Now will treat it as though you are loading an external URL and re-load the entire frame within the existing frame. Ironically, it does fill the data out, but you're left with a frame within a frame until you reload the URL.
I tried this using window.location, manually entering the URI into the gsft_main panel as above, and doing it server side with setRedirect and setRedirectURL. Every time I got it to redirect this was the behavior, so I decided to try to use GlideDialog to direct to a UI page containing a form to insert a record to the table.
Issues with GlideDialog
GlideDialog was promising, however it seems to be bugged for scoped apps. While there's a GlideDialog scoped API, the render() function seems to be dependent on a non-scoped API. Each time I would build the form and render it I would end up with an error stating an API was not in scope. I don't have it written in my notes, but I believe it was GlideMobileOrDesktop, or something like that. I believe it was trying to determine what type of device I was on in order to render the frame. This error would stop the UI Page client script from running, so the form would open but you would be unable to submit it.
Solution
I was ultimately able to fix this by using a client UI Action, a GlideAjax script, and the GlideDialogForm function. My UI Action grabs the sys_id of the form you're on and sends it to the GlideAjax, which runs a GlideQuery and pulls in the information I need. It then builds the data into an XML file and sends it back to the UI Action (standard GlideAjax stuff). From there I parse the XML and use g_form to write to the fields before rendering the dialog box. The box takes a couple seconds to load after clicking it, but it's fine for us since this a feature we don't expect people to be using very often. I've included my code below in case anybody is running into a similar issue. As a final note, we are currently running on Fuji.
UI Action
function setRedirection(){
//Call GlideAjax and parse XML response into local variables
var gajax = new GlideAjax('taskAjax');
gajax.addParam('sysparm_name', 'getIntakeValues');
gajax.addParam('sysparm_sys_id', g_form.getUniqueValue());
gajax.getXML(getResponse);
//Parse XML and write to form
function getResponse(response){
//Create Dialog form and add -1 to direct to new form
var dialog = new GlideDialogForm('Manual Task','scoped table');
dialog.setSysID(-1);
//Create callback for Dialog and load frame
dialog.setLoadCallback(function(iframeDoc) {
// To get the iframe: document.defaultView in non-IE, document.parentWindow in IE
var dialogFrame = 'defaultView' in iframeDoc ? iframeDoc.defaultView : iframeDoc.parentWindow;
dialogFrame.g_form.setValue('application',(response.responseXML.getElementsByTagName("application")[0].getAttribute('value')));
dialogFrame.g_form.setValue('request_type',(response.responseXML.getElementsByTagName("request_type")[0].getAttribute('value')));
dialogFrame.g_form.setValue('sub_type',(response.responseXML.getElementsByTagName("sub_type")[0].getAttribute('value')));
dialogFrame = null;
});
dialog.render();
}
}
GlideAjax
var taskAjax= Class.create();
dcoeManualTaskAjax.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
ajaxFunction_getIntakeValues : function(){
//Grabbing sys_id from client script
var sysID = this.getParameter('sysparm_sys_id');
//Calling private function to run glideQuery and save Intake values
this._query(sysID);
//Setting "result" message on XML
var result = this.newItem("Result");
result.setAttribute("message","returning intake values for " + this.number);
//Calling private function to build intake values into XML
this._setXMLValues("application",this.application);
this._setXMLValues("request_type",this.request_type);
this._setXMLValues("sub_type",this.sub_type);
},
_setXMLValues: function(name, value){
var setValue = this.newItem(name);
setValue.setAttribute('value',value);
},
_query: function(sysID){
var gr = new GlideRecord("x_mce_dcoe_intake_x_mce_dcoe_intakes");
gr.addQuery('sys_id',sysID);
gr.query();
while(gr.next()){
this.number = gr.number;
this.application = gr.application;
this.request_type = gr.request_type;
}
},
type: 'taskAjax'
});