- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-28-2025 08:42 AM
Hey guys,
I created the Hierarchy (Parent Topic and Child Topic - img1), it is correct, however, I need when the user clicks on ##NewTest4 Child Topic to directly open the form of the Catalog Item or Record Producer.
Currently, when the user clicks on Child Topic ##NewTest4, the "Card" appears with the Form at the bottom (img2), that is, the user needs to click on the "Card" again to open the form.
Note: I would like to know if there is a possibility for the user to click on ##NewTest4 Child Topic and directly open the Form?
I Connected Content (Catalog/RP Item) in ##NewTest4 Child Topic, but the form does not open automatically after click (img3 backend) > (img4 Portal)
Could anyone help me? please.
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-02-2025 07:31 AM
Hello @Elton2,
I'm doing well, thank you! How about you?
I have some good news—I was able to accomplish your requirement! However, to achieve this, we'll need to clone an OOTB widget called "Sub Topic".
Typically, parent and child topic cards are designed to navigate only between taxonomy pages. I have tested the backend code, and you can confirm with your client before proceeding with this approach. This change will not impact other functionality and will apply only to the "Sub Topic" widget.
After cloning, apply the following changes to the Server Script. I have added appropriate comments where I have made the changes.
(function() {
data.subTopics = [];
data.offset = 0;
data.limit = 0;
data.showMore = false;
data.lastTopic = true;
data.showMoreData = gs.getMessage("View all");
data.isMobileApp = $sp.getParameter('view') === 'mobile';
var fetchedSubTopics = [];
data.topicId = (input && input.topic_id) || options.topic_id || $sp.getParameter("topic_id");
data.subTopicHeader = gs.getMessage("{0} topics", getTopicName(data.topicId));
var urlEnabled = gs.getProperty("sn_ex_sp.enable.image.url.support");
function getTopicName(topicId) {
try {
var topicJs = new sn_taxonomy.Topic(topicId);
return topicJs.getName();
} catch (ex) {
gs.error(gs.getMessage("Invalid Topic Id."));
}
}
// Initial topic fetch on the basis of topic adjustments
if (input && input.action === "getInitSubTopics") {
var fetchLimit = input.topicLimit + 2;
try {
fetchedSubTopics = fetchSubTopics(input.topicId, 0, fetchLimit);
if (fetchedSubTopics.length > input.topicLimit) {
data.lastTopic = false;
}
data.subTopics = fetchedSubTopics;
} catch (ex) {
gs.addInfoMessage(gs.getMessage("You are either not authorized or record is not valid."));
}
}
// on click of view all fetching all topics
if (input && input.action === "viewAll") {
data.showMore = false;
data.subTopics = input.subTopics;
if (!input.lastTopic) {
fetchedSubTopics = fetchSubTopics(input.topicId, input.offset, 0);
data.subTopics = data.subTopics.concat(fetchedSubTopics);
}
}
//code update 1:
//created this new function to get the catalog item id
//It will return catalog id if the child topic has no further child topics and conected content has only one record and it has to be a catalog item
function getCatalogItem(topicId) {
var list = new GlideRecord("topic");
list.addQuery('parent_topic', topicId);
list.query();
if (!list.hasNext()) {
var content = new GlideRecord("m2m_connected_content");
content.addQuery('topic', topicId);
content.query();
while (content.next())
if (content.getRowCount() == 1 && content.content_type.name == 'Catalog Item') {
return content.catalog_item;
}
}
}
function fetchSubTopics(topicId, startWindow, endWindow) {
try {
var topicJs = new sn_taxonomy.Topic(topicId);
var childTopics = topicJs.getChildTopics(true, data.isMobileApp, endWindow, startWindow);
var topics = childTopics.topics;
var topicUtil = new sn_ex_sp.TopicPageUtil();
for (var i = 0; i < topics.length; i++) {
if (options.show_topic_icon === 'true') {
var icon;
if(urlEnabled && urlEnabled==="true")
icon = topicUtil.getIcon(topics[i].sys_id);
else
icon = sn_taxonomy.Topic.getIcon(topics[i].sys_id);
if (icon && icon.trim()) {
topics[i].icon = icon;
} else {
topics[i].icon = topicUtil.fetchDefaultIconImage();
}
}
//code update 2:
var catItemId=getCatalogItem(topics[i].sys_id);// stores the catalog id return by the func newly created.
// code update 3:
// we'll check if there is any id recieved
// if yes then we will add the link of catalog form to the child topic
// else it will work normally, it will redirect to a topic page
if(catItemId){
topics[i].link ='?id=sc_cat_item&sys_id='+catItemId;
}else{
var pageToRedirect = topics[i].template && topics[i].template.length > 0 ? topics[i].template : 'emp_taxonomy_topic';
topics[i].link = '?id='+ pageToRedirect +'&topic_id=' + topics[i].sys_id;
}
if (data.isMobileApp) {
topics[i].link = topics[i].link + '&view=mobile';
}
}
data.limit = childTopics.limit;
data.offset = childTopics.offset;
return topics;
} catch (ex) {
gs.error(gs.getMessage("Invalid Topic Id."));
}
}
})();
Now add the widget to the taxonomy page.
Output from my PDI.
I hope this helps resolve your issue!
Mark this as Helpful / Accept the Solution if this helps so that it helps future hunters too. 😊

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-28-2025 10:23 AM - edited 03-01-2025 09:41 AM
Hi @Elton2 ,
I feel this is the expected behavior in the ServiceNow ESC portal, allowing you to structure your topics using a parent-child relationship. If you want to directly associate a catalog item with a menu, you can use Quick Links in the top-level parent topic.
Mark this as Helpful / Accept the Solution if this helps.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-28-2025 11:12 AM - edited 02-28-2025 11:13 AM
Hi @Community Alums , how are you?!
I would like to thank you for the feedback.
I know about the "Quick Link", but I would like when the user clicks on the "Child Topic" they are directed
automatically to the "Form" (without having to click on the previous "Card")
Inside ##NewTest4 "Child Topic", there is a related list "Quick Link", but even creating "Quick Link" (img5 - Backend)
it is on the right side (img6 - Portal)
Try creating a "URL" field in the form and copying the URL of the Catalog Item or RP, but even So I can't do it.
Note: The customer wants to use the OOTB components, so I would like some guidance from you.
Best regards,

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-02-2025 07:31 AM
Hello @Elton2,
I'm doing well, thank you! How about you?
I have some good news—I was able to accomplish your requirement! However, to achieve this, we'll need to clone an OOTB widget called "Sub Topic".
Typically, parent and child topic cards are designed to navigate only between taxonomy pages. I have tested the backend code, and you can confirm with your client before proceeding with this approach. This change will not impact other functionality and will apply only to the "Sub Topic" widget.
After cloning, apply the following changes to the Server Script. I have added appropriate comments where I have made the changes.
(function() {
data.subTopics = [];
data.offset = 0;
data.limit = 0;
data.showMore = false;
data.lastTopic = true;
data.showMoreData = gs.getMessage("View all");
data.isMobileApp = $sp.getParameter('view') === 'mobile';
var fetchedSubTopics = [];
data.topicId = (input && input.topic_id) || options.topic_id || $sp.getParameter("topic_id");
data.subTopicHeader = gs.getMessage("{0} topics", getTopicName(data.topicId));
var urlEnabled = gs.getProperty("sn_ex_sp.enable.image.url.support");
function getTopicName(topicId) {
try {
var topicJs = new sn_taxonomy.Topic(topicId);
return topicJs.getName();
} catch (ex) {
gs.error(gs.getMessage("Invalid Topic Id."));
}
}
// Initial topic fetch on the basis of topic adjustments
if (input && input.action === "getInitSubTopics") {
var fetchLimit = input.topicLimit + 2;
try {
fetchedSubTopics = fetchSubTopics(input.topicId, 0, fetchLimit);
if (fetchedSubTopics.length > input.topicLimit) {
data.lastTopic = false;
}
data.subTopics = fetchedSubTopics;
} catch (ex) {
gs.addInfoMessage(gs.getMessage("You are either not authorized or record is not valid."));
}
}
// on click of view all fetching all topics
if (input && input.action === "viewAll") {
data.showMore = false;
data.subTopics = input.subTopics;
if (!input.lastTopic) {
fetchedSubTopics = fetchSubTopics(input.topicId, input.offset, 0);
data.subTopics = data.subTopics.concat(fetchedSubTopics);
}
}
//code update 1:
//created this new function to get the catalog item id
//It will return catalog id if the child topic has no further child topics and conected content has only one record and it has to be a catalog item
function getCatalogItem(topicId) {
var list = new GlideRecord("topic");
list.addQuery('parent_topic', topicId);
list.query();
if (!list.hasNext()) {
var content = new GlideRecord("m2m_connected_content");
content.addQuery('topic', topicId);
content.query();
while (content.next())
if (content.getRowCount() == 1 && content.content_type.name == 'Catalog Item') {
return content.catalog_item;
}
}
}
function fetchSubTopics(topicId, startWindow, endWindow) {
try {
var topicJs = new sn_taxonomy.Topic(topicId);
var childTopics = topicJs.getChildTopics(true, data.isMobileApp, endWindow, startWindow);
var topics = childTopics.topics;
var topicUtil = new sn_ex_sp.TopicPageUtil();
for (var i = 0; i < topics.length; i++) {
if (options.show_topic_icon === 'true') {
var icon;
if(urlEnabled && urlEnabled==="true")
icon = topicUtil.getIcon(topics[i].sys_id);
else
icon = sn_taxonomy.Topic.getIcon(topics[i].sys_id);
if (icon && icon.trim()) {
topics[i].icon = icon;
} else {
topics[i].icon = topicUtil.fetchDefaultIconImage();
}
}
//code update 2:
var catItemId=getCatalogItem(topics[i].sys_id);// stores the catalog id return by the func newly created.
// code update 3:
// we'll check if there is any id recieved
// if yes then we will add the link of catalog form to the child topic
// else it will work normally, it will redirect to a topic page
if(catItemId){
topics[i].link ='?id=sc_cat_item&sys_id='+catItemId;
}else{
var pageToRedirect = topics[i].template && topics[i].template.length > 0 ? topics[i].template : 'emp_taxonomy_topic';
topics[i].link = '?id='+ pageToRedirect +'&topic_id=' + topics[i].sys_id;
}
if (data.isMobileApp) {
topics[i].link = topics[i].link + '&view=mobile';
}
}
data.limit = childTopics.limit;
data.offset = childTopics.offset;
return topics;
} catch (ex) {
gs.error(gs.getMessage("Invalid Topic Id."));
}
}
})();
Now add the widget to the taxonomy page.
Output from my PDI.
I hope this helps resolve your issue!
Mark this as Helpful / Accept the Solution if this helps so that it helps future hunters too. 😊
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-02-2025 11:58 AM
Hi @Community Alums , I'm glad you are very well!
I'm good too! Thanks again 😉
I was studding about your suggestion, I believe that if I decide to clone this widget called "Sub Topic" and try make some changes in Server Script as you wrote, I hope it can working.
Tomorrow in Brazil is holiday, but next Tuesday I am going to see it with my Technical Lead and Customer.
Obs.: I'm so happy for your support and attention, I am going to return here asap.
Thanks again and have a great Sunday!
See you.