- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-15-2016 01:29 AM
Hi,
I'm new to the Service Portal and tried to customize the Header Menu.
After some research I found out that there is currently a problem with cloning the Header Menu.
I'm aware of the issue with the spDropdownTree directive and tried to create my own angular provider directive in the service portal as mentioned on https://github.com/service-portal/documentation/issues/50.
So far I created the following angular provider directive:
Type: Directive
Name: spDropdownCustom
/*! RESOURCE: /scripts/app.$sp/directive.spDropdownTree.js */
/* */
angular.module('sn.$sp').directive('spDropdownCustom', function () {
return {
restrict: 'E',
scope: {items: '='},
replace: true,
template: '<ul class="dropdown-menu">' +
'<li ng-repeat="mi in items" style="min-width: 20em;" ng-class="{\'dropdown-submenu\': mi.type == \'menu\', \'dropdown-menu-line\':$index < items.length - 1}" ng-include="getURL()">' +
'</ul>',
link : function(scope, element, attrs, controller) {
scope.getURL = function() {
return 'spDropdownTreeTemplate_custom';
}
}
}
});
After that, I changed the directive call in the menuTemplate and spDropdownTreeTemplate_custom from <sp-dropdown-tree to <-sp-dropdown-custom.
The templates are available on your instance under https://yourservicenowinstance.service-now.com/sp_ng_template_list.do?sysparm_query=&sysparm_first_r...
But my scripted list (OOTB Request Menu Entry) wont want to show the dropdown menu as seen in the following picture:
Does anyone know if my angular provider directive is correct or knows how I can get my dropdown to work again?
Maybe nathanfirth?
Solved! Go to Solution.
- 12,152 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-15-2016 01:52 AM
Okay so apparently I'm also new to angularjs and just found the article from Nathan about how to create an angular directive in service portal.
I removed the code "angular.module('sn.$sp').directive('spDropdownCustom'," and the corresponding bracket from the angular provider directive and the dropdown works fine again.
The final code of my directive is now:
- /*! RESOURCE: /scripts/app.$sp/directive.spDropdownTree.js */
- function () {
- return {
- restrict: 'E',
- scope: {items: '='},
- replace: true,
- template: '<ul class="dropdown-menu">' +
- '<li ng-repeat="mi in items" style="min-width: 20em;" ng-class="{\'dropdown-submenu\': mi.type == \'menu\', \'dropdown-menu-line\':$index < items.length - 1}" ng-include="getURL()">' +
- '</ul>',
- link : function(scope, element, attrs, controller) {
- scope.getURL = function() {
- return 'spDropdownTreeTemplate_custom';
- }
- }
- }
- };

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-10-2017 06:06 AM
I am having an issue with this as well. This was a helpful post in trying to explain what is going on with this. But I tried copying the text above for the provider, and I think I have done what I needed with redirecting the templates as well. But my menu just looks like it's loading for a few seconds and then changes the color of the menu, and rendors all links on the page inoperable. Can anyone see something I am missing? I really don't understand angular. The intent is for me to change the shopping cart, but I even took that part out for now just to try to get this to work. But I am obviously not understanding something.
I highlighted the parts that I changed to point to the custom angular. This is the code from the various parts of this attempted change.
ITSC Header Menu (HMTL)
<ul class="nav navbar-nav">
<div class="header-loader" ng-show="loadingIndicator">
<div class="hidden-xs sp-loading-indicator la-sm">
<div></div>
<div></div>
<div></div>
</div>
</div>
<li ng-repeat="item in data.menu.items" ng-class="{dropdown: item.items.length > 0}" ng-include="'ITSCmenuTemplate'"></li>
<!-- Shopping cart stuff -->
<li ng-if="options.enable_cart && data.isLoggedIn" class="dropdown hidden-xs">
<a href="javascript:void(0)"
data-toggle="dropdown"
id="cart-dropdown"
uib-tooltip-template="'item-added-tooltip.html'"
tooltip-placement="bottom"
tooltip-trigger="'none'"
tooltip-is-open="$parent.itemAddedTooltipOpen"
title="${Cart}">
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
<span ng-bind-html="'${Cart}'"></span>
<span ng-if="cartItemCount > 0" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
</a>
<div class="dropdown-menu cart-dropdown">
<sp-widget widget="data.cartWidget"></sp-widget>
</div>
</li>
<li ng-if="options.enable_cart && data.isLoggedIn" class="dropdown visible-xs">
<a href="?id=sc_cart"
title="${Cart}">
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
<span ng-bind-html="'${Cart}'"></span>
<span ng-if="cartItemCount > 0" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
</a>
</li>
<script>
<div ng-click="toggleCart()" class="item-added-tooltip">${Item has been added to your cart.}</div>
</script>
</ul>
Angular template - itscMenuTemplate
<a ng-if="item.items.length == 0 && !item.scriptedItems" ng-href="{{item.href}}" target="{{item.url_target}}">{{ item.label }}</a>
<a ng-if="item.items.length > 0" href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ item.label }} <span class="caret"></span></a>
<ul ng-if="item.items.length > 0" class="dropdown-menu" role="menu">
<li ng-repeat="item in item.items" ng-include="'itscMenuTemplate'" />
</ul>
<a ng-if="item.scriptedItems.count > 0" href="javascript:void(0)" data-toggle="dropdown" title="{{item.hint}}">
<span ng-bind-html="item.label"></span>
<span ng-if="!item.scriptedItems.omitBadge" class="label label-as-badge label-primary sp-navbar-badge-count">{{item.scriptedItems.count}}</span>
</a>
<itsc-sp-dropdown-tree ng-if="item.scriptedItems.count > 0" items="item.scriptedItems.items" />
Angular template - itscSpDropdownTreeTemplate
<a ng-if="mi.type == 'link'" title="{{mi.title}}" target="{{mi.target}}" href="{{mi.href}}">
{{mi.title | characters:60}}
</a>
<a ng-if="mi.type == 'record' && !mi.__page" title="{{mi.short_description}}" href="?id=ticket&table={{mi.__table}}&sys_id={{mi.sys_id}}">
<span>{{mi.short_description | characters:60}}</span>
<span class="block color-primary text-muted">
<span class="block" style="float: right">
<sn-time-ago timestamp="mi.sys_updated_on" />
</span>
{{mi.number}}
</span>
</a>
<a ng-if="mi.type == 'record' && mi.__page" title="{{mi.short_description}}" href="?id={{mi.__page}}&table={{mi.__table}}&sys_id={{mi.sys_id}}">
<span>{{mi.short_description | characters:60}}</span>
<span class="block color-primary text-muted">
<span class="block" style="float: right">
<sn-time-ago timestamp="mi.sys_updated_on" />
</span>
{{mi.number}}
</span>
</a>
<a ng-if="mi.type == 'request'" title="{{mi.short_description}}" href="?id=sc_request&table={{mi.__table}}&sys_id={{mi.sys_id}}">
<span>{{mi.short_description | characters:60}}</span>
<span class="block color-primary text-muted">
<span class="block" style="float: right">
<sn-time-ago timestamp="mi.sys_updated_on" />
</span>
{{mi.number}}
</span>
</a>
<a ng-if="mi.type == 'approval'" title="{{mi.short_description}}" href="?id=approval&table={{mi.__table}}&sys_id={{mi.sys_id}}">
<span ng-if="mi.short_description">{{mi.short_description | characters:60}}</span>
<span class="block color-primary text-muted">
<span class="block" style="float: right">
<sn-time-ago timestamp="mi.sys_updated_on" />
</span>
{{mi.number}}
</span>
</a>
<a ng-if="mi.type == 'menu' && mi.items.length" title="{{mi.title}}" href="javascript:void(0)" class="menu_trigger right-caret">
{{mi.title | characters:60}}
</a>
<itsc-sp-dropdown-tree ng-if="mi.type == 'menu' && mi.items.length" items="mi.items" />
Angular provider - type Directive - itscSpDropdownTree
/*! RESOURCE: /scripts/app.$sp/directive.spDropdownTree.js */
function () {
return {
restrict: 'E',
scope: {items: '='},
replace: true,
template: '<ul class="dropdown-menu">' +
'<li ng-repeat="mi in items" style="min-width: 20em;" ng-class="{\'dropdown-submenu\': mi.type == \'menu\', \'dropdown-menu-line\':$index < items.length - 1}" ng-include="getURL()">' +
'</ul>',
link : function(scope, element, attrs, controller) {
scope.getURL = function() {
return 'itscSpDropdownTreeTemplate';
}
}
}
};
(function($) {
$("body").on( "click", "a.menu_trigger", function(e) {
var current = $(this).next();
var grandparent = $(this).parent().parent();
if ($(this).hasClass('left-caret') || $(this).hasClass('right-caret'))
$(this).toggleClass('right-caret left-caret');
grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');
current.toggle();
$(".dropdown-menu").each(function(i, elem) {
var elemClosest = $(elem).closest('.dropdown');
var currentClosest = current.closest('.dropdown');
if (!elem.contains(current[0]) && elem != current[0] && (!currentClosest.length || !elemClosest.length || elemClosest[0] == currentClosest[0]))
$(elem).hide();
})
e.stopPropagation();
});
$("body").on( "click", "a:not(.menu_trigger)", function() {
var root=$(this).closest('.dropdown');
root.find('.left-caret').toggleClass('right-caret left-caret');
});
})(jQuery);
;
Thanks,
Shannon

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-11-2017 05:45 AM

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-19-2021 09:16 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-08-2018 04:50 AM
I wasted my whole day to find out what i am doing wrong... And then found this thread. At last able to replicate the header.. Thanks!!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-24-2018 06:59 PM
This post literally saved my day. Thanks to paku, suryanair, Shannon Burns for your comments.
Awesome...and THANK YOU.