- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-11-2025 02:48 AM
Hello everyone,
I have a task in the Service Portal that requires creating an "Add external comment" widget. When clicked, a modal opens for entering text. Once filled out, a flow should be launched to insert the comment as a public comment in the primary_ticket. This flow will be launched as a system user, and the public comment will indicate the person who wrote it.
I've already created the button, the modal, and the flow (which works correctly if I test it in the flow test section by giving it a sys_id from a Universal Request and entering the requested inputs). However, when I press submit on the modal, the flow doesn't run. I've checked the client side of the widget and it sends the correct data to the server side. I don't know if the server side of the widget is misconfigured or if the subflow needs to be "Callable by Client API," which is why it can't run (I haven't been able to test this part because it requires adding ACLs, and I don't have security_admin permissions).
Server Side:
// =================== Enviar comentario externo vÃa subflow ===================
if (input && input.action === 'add_external_comment') {
gs.info('INPUT desde cliente: ' + JSON.stringify(input));
var urSysId = input.ur_sys_id;
var commentText = input.comment_text;
if (!urSysId || !commentText) {
gs.error('Faltan datos: ur_sys_id o comment_text');
data.result = 'missing_data';
return;
}
try {
var inputs = {
'comment': commentText,
'ur_sys_id': urSysId
};
var flowAPI = new sn_fd.FlowAPI();
var execution = flowAPI.startSubflow('[ATC]Add External Comment to UR', inputs, 'system');
if (execution) {
gs.info('Subflow lanzado correctamente: ' + execution.getId());
data.result = 'comment_launched';
} else {
gs.error('No se pudo lanzar el subflow');
data.result = 'subflow_error';
}
} catch (e) {
gs.error('Error al ejecutar el subflow: ' + e.message);
data.result = 'exception';
}
return;
}
Client Side:
// ========== External Comment Modal ==========
c.openCommentModal = function() {
c.externalCommentText = '';
var options = {
size: 'md',
scope: $scope,
backdrop: 'static',
templateUrl: 'add-external-comment-template.html'
};
instance = $uibModal.open(options);
instance.rendered.then(function() {
var modal = $('div.modal');
modal.attr('aria-labelledby', 'modal-title');
});
};
// ========== Submit External Comment ==========
c.submitComment = function() {
if (!c.externalCommentText || c.externalCommentText.trim() === '') {
spUtil.addErrorMessage("El comentario no puede estar vacÃo.");
return;
}
c.server.update({
action: 'add_external_comment',
comment_text: c.externalCommentText.trim(),
author_name: c.data.currentUserName,
ur_sys_id: c.data.ur_sys_id
}).then(function(response) {
var result = response && response.data ? response.data.result : null;
if (result === 'comment_launched') {
spUtil.addInfoMessage("Comentario enviado correctamente.");
c.cancel();
} else {
spUtil.addErrorMessage("Error al lanzar el subflow. Código: " + result);
}
});
};
}
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-12-2025 05:12 AM
it should go in server side script of widget.
If my response helped please mark it correct and close the thread so that it benefits future readers.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-11-2025 03:02 AM
I already responded to your earlier question for same topic.
Your syntax to call subflow is wrong. see below points
logs are coming in the widget server side?
you can always use Create code snippet to get the script to trigger subflow from script
try {
var inputs = {};
inputs['mydate'] = ; // Date
inputs['mrvsdata'] = ; // Array.Object
// Start Asynchronously: Uncomment to run in background. Code snippet will not have access to outputs.
// sn_fd.FlowAPI.getRunner().subflow('global.testing_mrvs_subflow').inBackground().withInputs(inputs).run();
// Execute Synchronously: Run in foreground. Code snippet has access to outputs.
var result = sn_fd.FlowAPI.getRunner().subflow('global.testing_mrvs_subflow').inForeground().withInputs(inputs).run();
var outputs = result.getOutputs();
// Get Outputs:
// Note: outputs can only be retrieved when executing synchronously.
var myjsonstring = outputs['myjsonstring']; // String
} catch (ex) {
var message = ex.getMessage();
gs.error(message);
}
If my response helped please mark it correct and close the thread so that it benefits future readers.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-11-2025 03:17 AM
Sorry @Ankur Bawiskar @
I didn't understand your answer in the previous post. Now I see that "Code snippet to execute this Subflow" gives me the correct structure to call the subflow on the server side.
Thank you very much and sorry for the inconvenience.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-11-2025 03:27 AM
Glad to help.
If my response helped please mark it correct and close the thread so that it benefits future readers.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-11-2025 03:30 AM
I've modified the server side based on what you've told me and it's giving me this error: Error launching subflow. Code: null.
Server Side:
(function() {
try {
var inputs = {
author_name: input.author_name || gs.getUserDisplayName(),
comment_text: (input.comment_text || '').trim(),
ur_sys_id: input.ur_sys_id + ''
};
sn_fd.FlowAPI.getRunner()
.subflow('global.atcadd_external_comment_to_ur')
.inBackground()
.withInputs(inputs)
.run();
data.result = 'comment_launched';
gs.info('[ExternalComment] Subflow lanzado OK para UR=' + inputs.ur_sys_id, 'ExternalComment');
} catch (ex) {
gs.error('[ExternalComment] Error: ' + ex.message, 'ExternalComment');
data.result = 'error';
}
})();
Client Side:
// ========== External Comment Modal ==========
c.openCommentModal = function() {
c.externalCommentText = '';
var options = {
size: 'md',
scope: $scope,
backdrop: 'static',
templateUrl: 'add-external-comment-template.html'
};
instance = $uibModal.open(options);
instance.rendered.then(function() {
var modal = $('div.modal');
modal.attr('aria-labelledby', 'modal-title');
});
};
// ========== Submit External Comment ==========
c.submitComment = function() {
if (!c.externalCommentText || c.externalCommentText.trim() === '') {
spUtil.addErrorMessage("El comentario no puede estar vacÃo.");
return;
}
c.server.update({
action: 'add_external_comment',
comment_text: c.externalCommentText.trim(),
author_name: c.data.currentUserName,
ur_sys_id: c.data.ur_sys_id
}).then(function(response) {
var result = response && response.data ? response.data.result : null;
if (result === 'comment_launched') {
spUtil.addInfoMessage("Comentario enviado correctamente.");
c.cancel();
} else {
spUtil.addErrorMessage("Error al lanzar el subflow. Código: " + result);
}
});
};
}