Announcing the Global SNUG Board of Directors. Learn more here

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dvp
Mega Sage
Mega Sage

Today, I would like to explain how to only display the categories that are related to a catalog.

For this we need to update SC categories widget, SC Category Page as well as SC Popular items OOB widgets.

Before going into the widget, I would like to shed some light on a method available in $sp API getParameter returns the value of given key. This methods helps to retrieve the sys id of the selected catalog.

If you have observed in the part 1 of this article series, the anchor tag has the sys id of catalog in URL.

<a ng-href="?id=sc_home2&catalog_sys_id={{inc.sysid}}" class="panel-body block">

And $sp.getParameter('catalog_sys_id');   will get the sys id of the catalog.

Once we have the sys id of the catalog all we need to do is update the existing widgets with the above method and filter the categories.

Below is the Updated server code of the SC categories widget

(function() {

// populate the 'data' object

data.categories = [];

data.sc_catalog = $sp.getParameter('catalog_sys_id'); //$sp.getValue('sc_catalog');

   

  var sc_cat = new GlideRecord('sc_catalog');

  sc_cat.addQuery('sys_id', data.sc_catalog);

  sc_cat.query();

  while(sc_cat.next())

  {

  data.catalog_name = sc_cat.title.toString();

  }

options.category_layout = options.category_layout || "Nested";

if (options.page) {

  var pageGR = new GlideRecord("sp_page");

  options.page = (pageGR.get(options.page)) ? pageGR.getValue("id") : null;

} else {

  options.page = 'sc_category';

}

if (input && input.action === "retrieve_nested_categories") {

  var childCategoriesGR = buildSubcategoryGR(input.parentID);

  data.subcategories = retrieveCategoriesFromGR(childCategoriesGR);

  return ;

}

var sc = new GlideRecord('sc_category');

sc.addQuery('sys_class_name', 'sc_category');

sc.addActiveQuery();

sc.orderBy('title');

//data.sc_catalog = $sp.getParameter('catalog_sys_id'); //$sp.getValue('sc_catalog');

if (data.sc_catalog)

  sc.addQuery('sc_catalog', data.sc_catalog);

if (options.category_layout === "Nested")

  sc.addQuery('parent', '');

sc.query();

data.categories = retrieveCategoriesFromGR(sc);

// If the selected category is a subcategory, we need to

// open all it's parent categories

var selectedCategory = new GlideRecord("sc_category");

var categoryID = $sp.getParameter("sys_id");

if (!categoryID || !selectedCategory.get(categoryID))

  return;

var parentArr;

if (options.category_layout !== "Nested" || !selectedCategory.parent)

  parentArr = data.categories;

else

  parentArr = openParent(selectedCategory.getElement("parent").getRefRecord());

var selectedCategoryItem = findElementBySysID(parentArr, selectedCategory.getUniqueValue());

if (selectedCategoryItem)

  selectedCategoryItem.selected = true;

function openParent(gr) {

  var catItem;

  if (!gr.parent) {

  catItem = findElementBySysID(data.categories, gr.getUniqueValue());

  } else {

  var parentCategoryArr = openParent(gr.getElement("parent").getRefRecord());

  catItem = findElementBySysID(parentCategoryArr, gr.getUniqueValue());

  }

  if (!catItem)

  return [];

  var subcategoryGR = buildSubcategoryGR(catItem.sys_id);

  catItem.subcategories = retrieveCategoriesFromGR(subcategoryGR);

  catItem.showSubcategories = true;

  return catItem.subcategories;

}

function findElementBySysID(arr, id) {

  var foundElements = arr.filter(function(item) {

  return item.sys_id === id;

  });

  return (foundElements.length > 0) ? foundElements[0] : null;

}

function retrieveCategoriesFromGR(gr) {

  var categories = []

  while (gr.next()) {

  var category = retrieveCategoryFromGR(gr);

  if (category)

  categories.push(category);

  }

  return categories;

}

function retrieveCategoryFromGR(gr) {

  if (!$sp.canReadRecord("sc_category", gr.getUniqueValue()))

  return null;

  if (options.check_can_view != true && options.check_can_view != "true") {

  // use GlideAggregate by way of GlideRecordCounter, doesn't check canView on each item

  var count = new GlideRecordCounter('sc_cat_item_category');

  prepQuery(count, gr.getUniqueValue());

  var item_count = count.getCount();

  if (item_count > 0) {

  var cat = {};

  cat.title = gr.title.getDisplayValue();

  cat.sys_id = gr.getUniqueValue();

  cat.catalog_sys_id = gr.sc_catalog.sys_id.toString();

  cat.count = item_count;

  cat.parent = gr.parent.getDisplayValue();

  if (options.category_layout === "Nested")

  cat.isParentCategory = checkIsParentCategory(gr);

  return cat;

  }

  }

  if (options.check_can_view == true || options.check_can_view == "true") {

  // use GlideRecord, checking canView on each item

  var itemCat = new GlideRecord('sc_cat_item_category');

  prepQuery(itemCat, gr.getUniqueValue());

  itemCat.query();

  var validatedCount = 0;

  var checked = 0;

  while (itemCat.next()) {

  checked++;

  if ($sp.canReadRecord("sc_cat_item", itemCat.sc_cat_item))

  validatedCount++;

  // if user can't see the first 50 items in this category, give up

  if (validatedCount == 0 && checked == 50)

  break;

  // if omitting badges, and if we found one, work is done

  if (validatedCount > 0 && options.omit_badges)

  break;

  }

  if (validatedCount > 0) {

  var cat = {};

  cat.title = gr.title.getDisplayValue();

  cat.sys_id = gr.getUniqueValue();

  cat.catalog_sys_id = gr.sc_catalog.sys_id.toString();

  cat.count = validatedCount;

  cat.parent = gr.parent.getDisplayValue();

  if (options.category_layout === "Nested")

  cat.isParentCategory = checkIsParentCategory(gr);

  return cat;

  }

  }

  return null;

}

function prepQuery(gr, scUniqueValue) {

  gr.addQuery('sc_category', scUniqueValue);

  gr.addQuery('sc_cat_item.active', true);

  gr.addQuery('sc_cat_item.visible_standalone', true);

  gr.addQuery('sc_cat_item.sys_class_name', 'NOT IN', 'sc_cat_item_wizard');

}

function checkIsParentCategory(cat) {

  var count = new GlideRecordCounter('sc_category');

  count.addQuery('active', true);

  count.addQuery('parent', cat.getUniqueValue());

  return count.getCount() > 0;

}

function buildSubcategoryGR(parentID) {

  var subcategoryGR = new GlideRecord("sc_category");

  subcategoryGR.addActiveQuery();

  subcategoryGR.orderBy('title');

  var sc_catalog = data.sc_catalog; //$sp.getValue('sc_catalog');

  if (sc_catalog)

  subcategoryGR.addQuery('sc_catalog', sc_catalog);

  subcategoryGR.addQuery('parent', parentID);

  subcategoryGR.query();

  return subcategoryGR;

}

})();

Also, we need to update spCategoryListItem angular provider to show only the categories of a selected catalog

Below is the updated client script of category angular provider

function spCategoryListItem() {

return {

restrict: 'E',

scope: {

category: "=",

omitBadges: "=",

level: "=",

page: "=?"

},

replace: true,

template:     '<div ng-class="{\'indent-category\': indentCategory}">' +

'<a class="list-group-item" ng-class="{selected: category.selected}" href="?id={{page}}&sys_id={{::category.sys_id}}&catalog_sys_id={{::category.catalog_sys_id}}">' +

'<span ng-if="!omitBadges" class="label label-as-badge label-primary">{{::category.count}}</span>' +

'<i class="fa fa-fw text-muted" ng-class="{\'fa-folder\': !category.showSubcategories, \'fa-folder-open\': category.showSubcategories}" ng-if="category.isParentCategory" ng-click="toggleShowSubcategories($event)"></i>{{::category.title}}' +

'</a>' +

'<sp-category-list-item ng-if="category.showSubcategories" ng-repeat="subcategory in category.subcategories" category="subcategory" omit-badges="omitBadges" level="level + 1"></sp-category-list-item>' +

'</div>',

controller: function($scope) {

// We have to eventually stop indenting the categories.

// So, we're choosing to indent up to 3 times. Otherwise,

// there won't be enough room to show the category name.

$scope.indentCategory = ($scope.level > 0 && $scope.level < 4);

$scope.page = $scope.page || 'sc_category';

$scope.toggleShowSubcategories = function(e) {

  1. e.originalEvent.stopPropagation();
  2. e.originalEvent.preventDefault();

$scope.$emit("$sp.sc_category.retrieve_subcategories", $scope.category);

$scope.category.showSubcategories = !$scope.category.showSubcategories;

}

}

}

}

Once we have the widget ready, create a new page with id sc_home2 and add updated SC category widget the the left…

One may follow the similar steps to get the popular items. But keep in mind that existing popular items widget will only work for catalog items and not for record producers.

Screenshot pointing the the page id of a catalog homepage

find_real_file.png

find_real_file.png

                                                                                                                                                                                                  Catalog Homepage

Note: If a different name is used for page id other than sc_home2, update the same in multi catalog widget that was created in part 1 of this article

After user landed on the desired Catalog homepage and when the user picks any category on the left then URL will redirect to sc_category page. Below is the screenshot of the sc_category page with the widgets.

In order to support multi portal functionality, the category page needs to be updated with the widget mentioned below.

find_real_file.png

Below is the updated code for SC Category Page Widget

Server Code

(function() {

  data.category_id = $sp.getParameter("sys_id");

  data.showPrices = $sp.showCatalogPrices();

  if (options && options.sys_id)

  data.category_id = options.sys_id;

  data.sc_catalog = $sp.getParameter('catalog_sys_id');

  var sc_cat = new GlideRecord('sc_catalog');

  sc_cat.addQuery('sys_id', data.sc_catalog);

  sc_cat.query();

  while(sc_cat.next())

  {

  data.catalog_name = sc_cat.title.toString();

  data.catalog_url = 'sc_home2&catalog_sys_id=' + sc_cat.sys_id.toString();

  }

// data.sc_catalog_page = $sp.getDisplayValue("sc_catalog_page") || "oa_sc_home2";

  // Does user have permission to see this category?

  if (!$sp.canReadRecord("sc_category", data.category_id)) {

  data.error = "You do not have permission to see this category";

  return;

  }

  var cat = new GlideRecord('sc_category');

  cat.get(data.category_id);

  data.category = cat.getDisplayValue('title');

  var items = data.items = [];

  var sc = new GlideRecord('sc_cat_item_category');

  if (data.category_id)

  sc.addQuery('sc_category', data.category_id);

  sc.addQuery('sc_cat_item.active',true);

  sc.addQuery('sc_cat_item.sys_class_name', 'NOT IN', 'sc_cat_item_wizard');

  sc.orderBy('sc_cat_item.order');

  sc.orderBy('sc_cat_item.name');

  sc.query();

  while (sc.next()) {

  // Does user have permission to see this item?

  if (!$sp.canReadRecord("sc_cat_item", sc.sc_cat_item.sys_id.getDisplayValue()))

  continue;

  var item = {};

  var gr = new GlideRecord('sc_cat_item');

  gr.get(sc.sc_cat_item);

  gr = GlideScriptRecordUtil.get(gr).getRealRecord();

  $sp.getRecordDisplayValues(item, gr, 'name,short_description,picture,price,sys_id');

  item.sys_class_name = sc.sc_cat_item.sys_class_name + "";

  item.page = 'sc_cat_item';

  if (item.sys_class_name == 'sc_cat_item_guide')

  item.page = 'sc_cat_item_guide';

  else if (item.sys_class_name == 'sc_cat_item_content') {

  $sp.getRecordValues(item, gr, 'url,content_type,kb_article');

  if (item.content_type == 'kb') {

  item.page = 'kb_article';

  item.sys_id = item.kb_article;

  } else if (item.content_type == 'literal') {

  item.page = 'sc_cat_item';

  } else if (item.content_type == 'external')

  item.target = '_blank';

  }

  items.push(item);

  }

})()

Once we have all the widgets needed, all we need to do is use the updated widgets on the page.

For this, follow the below steps

  1. Open sc_category page
  2. Open the Instance of SC categories widget and update the widget   reference field with multi categories widget that was created earlier.

find_real_file.png

this concludes the part 2 of multi catalog functionality in Service Portal. In the next part, I will delve into Search and Breadcrumbs functionalities that supports multi catalogs.

Attached are the XML files of the following Widgets

  • Multi SC Categories
  • Multi SC Popular Items
  • Multi SC Category Page

Blogs in this series:

Portal diaries: Service Portal — Multiple Catalogs (Part 1)

19 Comments