Announcing the Global SNUG Board of Directors. Learn more here

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
mhedtke24
Tera Expert

In this article we will look at how we can create favorites in the service portal.

To do this we need to build the following:

  • Widget to mark pages as a favorite
  • Widget to list the favorites
  • Portal page to display the list of favorites
  • Header menu to list the favorites

Favorite Marker Widget

This is the widget that will be added to the pages you want people to be able to mark as a favorite.

Note: This will create a favorite in the navigation menu in the platform UI outside of the Service Portal as well.

Name: Favorite Marker

ID: favorite_marker

HTML Template:

<button ng-click="c.update()" 
          type="button" 
          class="btn btn-outline-secondary btn-sm" 
          style="font-size:1.5em">
    <i ng-class="c.data.favIcon"
       uib-tooltip="{{c.data.tooltip}}"
       tooltip-placement="left"
       tooltip-append-to-body="true">
    </i>
</button>

CSS:

button {
	background-color: #fff;
}

Client Controller:

function($scope, $window, $document) {
  /* widget controller */
  var c = this;
	
	var pathUrl = $window.location.pathname;
	var queryUrl = $window.location.search;

	c.data.name = c.options.title;
	c.data.icon = c.options.glyph;
	c.data.url = pathUrl + queryUrl;
	
	c.server.get({checkUrl: true,url: c.data.url}).then(function(r) {
		c.data.bookmark = r.data.bookmark;
		c.data.favIcon = r.data.favIcon;
		c.data.bookmarkId = r.data.bookmarkId;
		c.data.tooltip = r.data.tooltip;
	});
	
	c.update = function() {

		if(c.data.bookmark == true) {
			c.server.get({bookmark: true,bookmarkId: c.data.bookmarkId}).then(function(r) {
				c.data.bookmark = r.data.bookmark;
				c.data.favIcon = r.data.favIcon;
				c.data.bookmarkId = r.data.bookmarkId;
				c.data.tooltip = r.data.tooltip;
			});

		} else {
			c.server.get({bookmark: false,url: c.data.url, title: c.data.name,icon: c.data.icon}).then(function(r) {			
				c.data.bookmark = r.data.bookmark;
				c.data.favIcon = r.data.favIcon;
				c.data.bookmarkId = r.data.bookmarkId;
				c.data.tooltip = r.data.tooltip;
			});
		}
	}
}

Server Script:

(function() {

	data.favIcon = 'fa fa-star-o';

})();

function getUrlVars(input) {
	var vars = {};
	var parts = input.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
		vars[key] = value;
	});
	return vars;
}

//Remove or add to favorite
if(input) {
	if(input.checkUrl) {

		var bookmarkGR = new GlideRecord('sys_ui_bookmark');
		bookmarkGR.addQuery('user', gs.getUserID());
		bookmarkGR.addQuery('url', input.url);
		bookmarkGR.query();

		if(bookmarkGR.hasNext()) {
			//Found the bookmark, select it
			bookmarkGR.next();
			data.bookmark = true;
			data.bookmarkId = bookmarkGR.getUniqueValue();
			data.favIcon = 'fa fa-star';
			data.tooltip = 'Remove from favorites';
		} else {
			//No bookmark found
			data.bookmark = false;
			data.favIcon = 'fa fa-star-o';
			data.tooltip = 'Add as a favorite';
		}
	}

	if(input.bookmark == false) {
		//Create a new bookmark
		var bookmarkGR = new GlideRecord('sys_ui_bookmark');
		bookmarkGR.initialize();
		bookmarkGR.user = gs.getUserID();
		
		if (input.title == 'Catalog Item'){
			var nameSysID = getUrlVars(input.url)['sys_id'];
			
			var bookmarkGR2 = new GlideRecord('sc_cat_item');
			bookmarkGR2.initialize();
			bookmarkGR2.addQuery('sys_id',nameSysID);
			bookmarkGR2.query();
			while (bookmarkGR2.next()) {
				bookmarkGR.title = bookmarkGR2.getDisplayValue('name');
			}
			
		} else {

			if (input.title == 'Ticket'){
				var nameTable = getUrlVars(input.url)['table'];
				if (nameTable == null){
					nameTable = 'kb_knowledge';
				}
				if (nameTable == 'kb_knowledge'){
					var nameSysID = getUrlVars(input.url)['sys_kb_id'];
				}else{
					var nameSysID = getUrlVars(input.url)['sys_id'];
				}


				var bookmarkGR2 = new GlideRecord(nameTable);
				bookmarkGR2.initialize();
				bookmarkGR2.addQuery('sys_id',nameSysID);
				bookmarkGR2.query();
				while (bookmarkGR2.next()) {
					bookmarkGR.title = bookmarkGR2.getDisplayValue('short_description');

				}
			} else {	
				bookmarkGR.title = input.title;
			}
		}

		bookmarkGR.url = input.url;

		if(input.icon) {
			bookmarkGR.icon = input.icon;
		} else {
			bookmarkGR.icon = 'tack';
		}
		var bookmarkId = bookmarkGR.insert();
		if(bookmarkId) {
			data.bookmark = true;
			data.bookmarkId = bookmarkId;
			data.favIcon = 'fa fa-star';
			data.tooltip = 'Remove from favorites';
		}
	}

	if(input.bookmark == true ) {
		var bookmarkGR = new GlideRecord('sys_ui_bookmark');
		bookmarkGR.get(input.bookmarkId);

		bookmarkGR.deleteRecord();

		data.bookmark = false;
		data.favIcon = 'fa fa-star-o';
		data.tooltip = 'Add as a favorite';
		data.bookmarkId = '';
	}
}

We added this widget next to the breadcrumbs widget on our pages.

find_real_file.png

Update: After you have added this to the pages you want people to be able to bookmark, you will need to go to the widget in the platform and set the "Title" of the instances in the Instances related list.  Make sure it matches what is listed in the server script "if" statements that check the input.title.

Example: The "if (input.title == 'Catalog Item')", the instance title for the widget should be called "Catalog Item".

find_real_file.png

Favorite List Widget

This widget is used to display the list of Service Portal favorites the user has marked.

Name: Favorite List

ID: favorite_list

HTML Template:

<div>

  <div class="panel-heading" >
    <label class="panel-title">
      <i class="fa fa-star m-r-sm"></i>
    </label>
  </div>


  <div class="list-group" >
    <div ng-if="c.data.fav.hasAny == false" class="list-group-item">
      ${ You do not have any favorites }
    </div>
    <div class="list-group-item" ng-repeat="item in c.data.fav" >
      <a ng-href="{{::item.url}}">{{item.short_description}}</a><i class="fa fa-times-circle fav-icon" 
                                                                   ng-click="c.removeFav(item.sys_id)"
                                                                   uib-tooltip="Remove from favorites" tooltip-placement="right" tooltip-append-to-body="true"></i>
    </div>
  </div>

</div>

CSS:

.fav-icon {
  float: right;
  font-size: 17px;
}
.fav-icon:hover {
  color: red;
}

.panel-heading {
  background-color: #b1b1b1;
  color: #ffffff;
}

Client Controller:

function($scope,spUtil) {

	var c = this;
	
	if (c.data.fav.length > 0) {
		c.data.fav.hasAny = true;
	}
	else {
		c.data.fav.hasAny = false;
	}

	c.removeFav = function(value) {
		c.data.remove = value;
		c.server.update()         
		spUtil.update($scope);
	}
}

Server Script:

(function() {

	var t = data;
	var z = new GlideRecord('sys_ui_bookmark');
	z.addQuery('user', gs.getUserID());
	z.addQuery('url', 'STARTSWITH', '/sp?');
	z.orderByDesc('sys_created_on');
	z.query();
	t.rowCount = z.getRowCount();
	t.fav = [];

	while (z.next()) {
		var a = {};
		a.short_description = z.getValue('title');
		a.sys_id = z.getValue('sys_id');
		a.url = z.getValue('url');
		t.fav.push(a);
	}

	// Delete favorite
	if (input && input.remove) {
		var bmGR = new GlideRecord('sys_ui_bookmark');
		bmGR.addQuery('user', gs.getUserID());
		bmGR.addQuery('sys_id', input.remove);
		bmGR.query();
		if (bmGR.next()) {
			bmGR.deleteRecord();
		}
	}
})();

Now you just need to create a page to add the Favorite List widget to.

find_real_file.png

Create Favorites Header Menu

Navigate to Service Portal > Menus and open the record that is tied to your Service Portal. In the Menu Items related list, click New.

Label: Favorites

Type: Scripted List

Condition: gs.isLoggedIn()

Server Script:

// maximum number of entries in this Menu
var max = 30;

var t = data; // shortcut
t.items = [];
var u = gs.getUser().getID();

// use record watchers to tell header when to update dropdown counts
t.record_watchers = [];
t.record_watchers.push({'table':'sys_ui_bookmark','filter':'urlSTARTSWITH/sp?^user=' + u});

var b = new GlideRecord('sys_ui_bookmark');
b.addQuery('user', gs.getUserID());
b.addQuery('url', 'STARTSWITH', '/sp?');
b.orderByDesc('sys_created_on');
b.setLimit(max);
b.query();
while (b.next()) {
  var a = {};
  
  a.type = 'link';
  a.title = b.getValue('title');
  a.href = b.getValue('url');
  t.items.push(a);
}

t.items = t.items.slice(0, max); // only want first 30
t.count = t.items.length;

var link = {title: gs.getMessage('View all favorites'), type: 'link', href: '?id=my_favorites', items: []};
t.items.unshift(link); // put 'View all favorites' first

Note: for the link to the View all favorites, make sure that you replace ?id=my_favorites with the page ID you created.

find_real_file.png

Comments
p_espinar
Kilo Guru

Thank you, mhedtke24, your customization looks very promising, but IMHO your article will benefit a lot with some screenshots of the results.

Un saludo,

Pablo Espinar

Consultant at Econocom Spain

mhedtke24
Tera Expert

I have added images to the article.  When I first attempted to add images to the article, they weren't displaying as to why I initially omitted them.

3ric
Kilo Expert

Thank you again for posting this.

 

I did find a weird issue for non-itil users. 

 

This line in the Server Script and the menu item wasn't working:

.addQuery('url', 'STARTSWITH', '/sp?');

For whatever reason a user without ITIL was generating bookmarks that started '/sp/?' instead of '/sp?'

 

Changing that addQuery to this fixed it

.addQuery('url', 'STARTSWITH', '/sp');
boosted
Mega Expert

thanks @mhedtke24 this is great! 

I was seeing a warning in the server script for the Favorite Marker widget "[sys_id] is better written in dot notation"

I replaced :
var nameSysID = getUrlVars(input.url)['sys_id'];

with this:
var nameSysID = $sp.getParameter("sys_id");


 
find_real_file.png

 

 

Aric5
Mega Expert

I love this solution, but I'm having a couple of issues that hopefully you can assist with.

1. The Favorites Widget is not displaying the bookmark entry title.  I've tried a few things, but can't get it to display.  Admittedly, portal is not my area of expertise.  However, it is important to note that the number of entries showing is correct and the x functionality appears to work swimmingly.

find_real_file.png
2.) The favorites menu item provides the correct count, but does nothing on mouse-over or click.
find_real_file.png

3ric
Kilo Expert

If the header link goes nowhere you will need to make sure that you have a page called "my_favorites" or to edit the second to last line of that script to point to the correct page.

For the entries not showing up in the list, make sure that the "title" is correct in your Bookmark table.

D Dejesus
Tera Contributor

He forgot to fill in some of the html on the Favorite List widget

 

Replace

<a ng-href=""></a><i class="fa fa-times-circle fav-icon" ng-click="c.removeFav(item.sys_id)" uib-tooltip="Remove from favorites" tooltip-placement="right" tooltip-append-to-body="true"></i>

 

With something like

 <a ng-href={{item.url}}>{{item.short_description}}</a><i class="fa fa-times-circle fav-icon" ng-click="c.removeFav(item.sys_id)" uib-tooltip="Remove from favorites" tooltip-placement="right" tooltip-append-to-body="true"></i>

 And it'll work just fine.

mhedtke24
Tera Expert

Thanks for posting this. I went to update the article, but it won't let me anymore and the code shows correctly when in edit mode, not sure why it isn't showing the code properly. I may need to re-post it as a different article.

Moedeb
Mega Guru

So I have also followed these instructions and like aric.wilber had the issue with not showing a title I am having the same issue.

 

I do not at all understand the comment that D Dejesus made unfortunately so therefore can't use that to fix the issue, is someone able to better explain exactly where and how I get the favorites list to actually display a name for what it is.

There is a list, the links to the favorites work, it simply displays a blank title.

mhedtke24
Tera Expert

For some reason it isn't displaying the code. But here is what it should look like to display the text of the Favorited item in the favorites list:

find_real_file.png

Make sure that the <a> tag looks like this: <a ng-href="{{::item.url}}">{{item.short_description}}</a>

mhedtke24
Tera Expert

Looks like it is filtering out the angular code, but you can see it in the screen shot i uploaded here.

Moedeb
Mega Guru

Thanks very much for your reply and the screen shot of the code, I was missing some.

I have added what you suggested and still have the same issue, so here are screen shots of what I have set up.

I have only included the favorite list widget as it appears the favorite Marker widget is working as intended.

find_real_file.png

find_real_file.png

Really appreciate the help.

mhedtke24
Tera Expert

Code looks right, did you try removing the widget from the page and re-adding it after updating the code in the widget?

Also did you go to the Favorite Marker Widget and in the related list for the Instances, set the "Title" for the pages the widget is on to mark favorites?

Moedeb
Mega Guru

Ok, so I hadn't updated the instance title, they were all blank.

I have updated them to appear to what I think they should be and that works great now for the Catalog Item which I have an instance of the favorite marker widget on, but I cannot get it to work at all on the knowledge articles.
   
I noticed the code:

if (input.title == 'Ticket'){
    var nameTable = getUrlVars(input.url)['table'];
    if (nameTable == null){
     nameTable = 'kb_knowledge';
    }
    if (nameTable == 'kb_knowledge'){
     var nameSysID = getUrlVars(input.url)['sys_kb_id'];
    }else{
     var nameSysID = getUrlVars(input.url)['sys_id'];
    }

 

So tried Ticket, tried kb_knowledge and also just Knowledge by adding the same code again and updating the title and nametable, without any success.

 

Sorry to keep being a pain, any other ideas?

mhedtke24
Tera Expert

The title should be Ticket for the knowledge instance of the widget.

Moedeb
Mega Guru

Ok, so worked it out, the issue wasn't "ticket" it was the tablename - rather than KB_knowledge it needed to be kb_article

 

So updated that and it is now all working great.

 

Thanks very much for your help - I really appreciate it and love the favorite widgets / functionality.

mhedtke24
Tera Expert

Great. Glad it is working for you now.

Rupa2
Tera Contributor

Thank you for the Article;I am able to add Bookmark and List of favorites in new page; 

however, I am struggling with couple things: 

1. When I add article to favorite and go out and come back, star is not blocked; it is showing white as if this was no bookmarked.

2. when I add again, it is allowing me to add as favorite again, which  results in listing as duplicate

3. When I try to Remove from favorites page, it gives error as cross scope privilege is required, though I added  Cross scope application as well as permissions on bookmark able.

 

Can you please help, if anyone have encountered similar issues ?

 

Rupa2
Tera Contributor

kb_article is not even a valid table; For me it worked with 'kb_knowledge'; I just updates Server script as title was inserting as blank in bookmark table, I forced to assign kb_knowledge as table name:

if (input.title == 'Ticket' || input.title == null){
var nameTable = getUrlVars(input.url)['table'];
if (nameTable == null){
nameTable = 'kb_knowledge';
}
if (nameTable == 'kb_knowledge'){
var nameSysID = getUrlVars(input.url)['sys_kb_id'];
}else{
var nameSysID = getUrlVars(input.url)['sys_id'];
}

Kim Sullivan
Mega Guru
This is awesome! Feature request- could the menu widget be made into a page widget, that way they would see their favorites on the screen without clicking into a sub-menu? Like Google does on their home page.
Deepika35
Kilo Contributor

After following all step I am still not able to see short_description for my Knowledge Portal though I have added

<a ng-href="{{::item.url}}">{{item.sys_id}} - {{item.short_description}}</a>

I can see sys_id coming but short_description is coming as empty.

 

Please help as it is urgent!!

Rupa2
Tera Contributor

Hi Deepika,

Confirm if Short description is actually inserting into 'Title' column in bookmarks, by going to System Definition -> Bookmarks

If no, then your favorite icon logic need to be fixed. 

If yes, then verify your My Favorites widget for below code:

 

Server Script:

(function() {

var t = data;
var z = new GlideRecord('sys_ui_bookmark');
z.addQuery('user', gs.getUserID());
//z.addQuery('url', 'STARTSWITH', '/sp?');
z.addQuery('url', 'STARTSWITH', '/csm?');
//z.orderByDesc('sys_created_on');
z.orderBy('title');
z.query();
t.rowCount = z.getRowCount();
t.fav = [];

while (z.next()) {
var a = {};
a.short_description = z.getValue('title');
a.sys_id = z.getValue('sys_id');
//a.sys_id = z.getValue('number');
a.url = z.getValue('url');
t.fav.push(a);
}

// Delete favorite
if (input && input.remove) {
var bmGR = new GlideRecord('sys_ui_bookmark');
bmGR.addQuery('user', gs.getUserID());
bmGR.addQuery('sys_id', input.remove);
// bmGR.addQuery('number', input.remove);
bmGR.query();
if (bmGR.next()) {
bmGR.deleteRecord();
}
}
})();

 

Client Script:

 

function($scope,spUtil) {

var c = this;
//c.template = "kb_article_list_template";
if (c.data.fav.length > 0) {
c.data.fav.hasAny = true;
}
else {
c.data.fav.hasAny = false;
}

c.removeFav = function(value) {
c.data.remove = value;
c.server.update()
spUtil.update($scope);
}
}

 

HTML Template

<div class="panel panel-{{::options.color}} b">
<div class="panel-heading">
<h4 class="panel-title">{{::options.title}}</h4>
</div>
<div class="list-group" >
<div ng-if="c.data.fav.hasAny == false" class="list-group-item">
${ You do not have any favorites }
</div>
<div class="list-group-item" ng-repeat="item in c.data.fav" >
<a ng-href="{{::item.url}}">{{item.short_description}}</a><i class="fa fa-times-circle fav-icon" ng-click="c.removeFav(item.sys_id)" uib-tooltip="Remove from favorites" tooltip-placement="right" tooltip-append-to-body="true"></i>
</div>
</div>
</div>

Deepika35
Kilo Contributor

Thanks for replying.
My issue is resolved now. I was adding wrong sys_id

tetra
Kilo Explorer

Hi Rupa, were you able to resolve the issue about the star showing as not blocked when you return to the page. I am facing the same issue and I would appreciate your kind feedback

Fei1
Kilo Contributor

Thanks for the great solution. It works well.

I only have one issue, if I favorite more than one catalog item (for laptop, phone, email), it looks like this.  

Is there anyway that I could display the item title instead of the instance title?

 

Alex23
Kilo Guru

Hi All,

Has anyone had an issue where a non-ITIL user/a user with no role can't use this?

When clicking the star it gets greyed out, but the favourite doesn't get added to the list.

No issue with ITIL users.

Anyone have any ideas what could be causing this?

Thanks!
Alex

Teddy Sincire2
Tera Expert

Hi Alex,

My guess would be a missing ACL?

Teddy

Rajesh44
Tera Expert

If I click on favorites marker every time. I have to enter the title field in sys_ui_bookmark table manually. Is there any method to auto-populate that ?

Rupa2
Tera Contributor

All our users are non-ITIL and have no issues. The only role they have is snc_internal. 

Reddy
Tera Guru

@alex Did you find any solution? I'm having the same issue.

Pavel87
Kilo Contributor

Hi All,

I am using this widget since two years already, had to a little bit adopt it to my environment, but it's working like a charm. This year someone noticed that when you copy KB as permalink, open it (via permalink of course) and try to add it to favorites, it is being added, but title is missing, whole favorite record looks like empty one.

Normally the hyperlink of KB article contains sys id of the record, but via permalink it's different, instead of sys_id it contains KB number, as below:

https://companyname.service-now.com/sp?id=kb_article_view&sysparm_article=KBnumber

Do you have any ideas how to make it work also for KB's as permalinks?

Server script that I am using for Favorite Marker widget looks as below for KBs

if (input.title == 'Ticket'){
				var nameTable = getUrlVars(input.url)['table'];
				if (nameTable == null){
					nameTable = 'kb_knowledge';
				}
				if (nameTable == 'kb_knowledge'){
					var nameSysID = getUrlVars(input.url)['sys_kb_id'];
				}else{
					var nameSysID = getUrlVars(input.url)['sys_id'];
				}


				var bookmarkGR2 = new GlideRecord(nameTable);
				bookmarkGR2.initialize();
				bookmarkGR2.addQuery('sys_id',nameSysID);
				bookmarkGR2.query();
				while (bookmarkGR2.next()) {
					bookmarkGR.title = bookmarkGR2.getDisplayValue('number') + ' - '+ bookmarkGR2.getDisplayValue('short_description');

				}
			} 

It looks like that when you add KB into favorites from permalink (and at the bottom from the standard link). These are two same KB articles added from different links

find_real_file.png

 

Thanks in advance

 

Pavel87
Kilo Contributor

@mhedtke24 Will you be able to advise something on my case? Sorry for asking you directly. Feature itself is working like a charm since 2 years in our environment, it is just not working correctly when adding KB articles via permalinks (we have versioning activated).

 

Thanks in advance

Matt77
Tera Expert

Hi @Pavel87 I have made some enhancements with the favorites where you don't need to update the Title of the instance after you add to a portal page. Also I have updated the code to account for using perma links on knowledge articles. Basically looking at the URL and creating the perma link version when adding the bookmark.

if (gs.action.getGlideURI().toString().indexOf('sys_kb_id')) {
				var kbSysId = gs.action.getGlideURI().getMap().get('sys_kb_id');
				var portalPage = $sp.getPortalRecord().getDisplayValue("url_suffix");
				var kbGR = new GlideRecord('kb_knowledge');
				kbGR.get(kbSysId);
				bmkGR.url = '/' + portalPage + '?id=kb_article_view&sysparm_article=' + kbGR.getValue('number');
			} else {
				bmkGR.url = input.url;
			}

 

See attached for updated widgets. Also I did add a custom string field on the bookmark table to capture the bookmark type. If you don't want that  you could update the code in the widget to remove it.

paweljaciow
Tera Contributor

Hi Matt,

Thank you very much for advices, you've saved my life 🙂

Thanks once again!

jjones4773
Giga Guru

Did anyone resolve the issue for Favorites populating for non ITIL users?   I'm having this issue.

Thanks.

Version history
Last update:
‎11-09-2018 07:55 AM
Updated by: