62 views

Description

Service Portal - Lookup Select Box variable with advanced reference qualifier breaks a catalog item with too many variables - 400 error

a GET is used to retrieve Lookup Select Box choices when a POST would be better to avoid this limit. 

Steps to Reproduce

1) Create a catalog item with 60 variables, one of them named "aaa"
2) create a Lookup Select Box variable on the same item with the following:
   table = sys_user
   reference qualifier = javascript:"first_nameCONTAINS" + current.variable_pool.aaa
3) view the item in Service Portal
4) populate the "aaa" variable
Notice a 400 error in the browser console, note the URL for the GET request is very long.

Workaround

The workaround requires overriding an AngularJS directive. This is a *temporary* solution. you need to manually disable or delete this dependency once the fix is available in an upgrade. 

1) Go to the platform UI and click the "Service Portal > Widgets" module

2) Search for the "SC Catalog Item" widget.

3) Go to Related Lists and create a new Dependency.

4) Name: spChoiceListOverride (or any other)

5) Submit

6) Click on the new dependency created "spChoiceListOverride"

7) Add new JS Includes, Display Name: spChoiceListOverride

8) Click on the magnifying glass to add a new UI Script. API Name: spChoiceListOverride

9) Script Content:

 

/* Script Content Starts Here */

angular.module('sn.$sp').config(function($provide) {

$provide.decorator('spChoiceListDirective', ['$delegate', 'spUtil', '$http', '$timeout', function($delegate, spUtil, $http, $timeout) {

var directive = $delegate[0];

 

var link = function (scope, element, attrs, ngModel) {

scope.getVal = function(v) {

return v;

};

 

var g_form = scope.getGlideForm();

var field = scope.field;

var fieldOptions;

 

scope.fieldValue = function() {

return field.value;

};

 

// Refresh the choice list if this field's reference qualifier contains the changing field's name

// or if this field is dependent on the changed field

g_form.$private.events.on('change', function(fieldName, oldValue, newValue) {

if (fieldName == field.name) {

 

}else if (fieldName == field.dependentField) {

field.dependentValue = newValue;

refreshChoiceList();

} else if ('variable_name' in field && field.reference_qual && field.reference_qual.indexOf(fieldName) != -1) {

refreshReferenceChoices();

}

});

 

function refreshChoiceList() {

var params = {};

params.table = g_form.getTableName();

params.field = field.name;

params.sysparm_dependent_value = field.dependentValue;

params.sysparm_type = choice_list_data;

var url = spUtil.getURL(params);

return $http.get(url).success(function(data) {

field.choices = [];

angular.forEach(data.items, function(item){

field.choices.push(item);

});

selectValueOrNone();

});

}

 

function selectValueOrNone() {

var hasSelectedValue = false;

angular.forEach(field.choices, function(c) {

if (field.value == c.value)

hasSelectedValue = true;

});

 

// If the choice list doesn't contain the current model value, just use the first choice

if (!hasSelectedValue && field.choices.length > 0 && (field.choice == ChoiceType.DropdownWithNone || field.choice == ChoiceType.DropdownWithoutNone))

g_form.setValue(field.name, field.choices[0].value, field.choices[0].label);

}

 

function refreshReferenceChoices() {

var params = {};

params['qualifier'] = field.reference_qual;

params['table'] = field.lookup_table;

params['sysparm_include_variables'] = true;

params['variable_ids'] = field.sys_id;

var getFieldSequence = g_form.$private.options('getFieldSequence');

if (getFieldSequence) {

params['variable_sequence1'] = getFieldSequence();

}

var itemSysId = g_form.$private.options('itemSysId');

params['sysparm_id'] = itemSysId;

var getFieldParams = g_form.$private.options('getFieldParams');

if (getFieldParams) {

angular.extend(params, getFieldParams());

}

 

params.sysparm_type = 'sp_ref_list_data';

var url = spUtil.getURL('sp_ref_list_data');

url = url.replace("sysparm_type=$sp", "sysparm_type=sp_ref_list_data");

return $http.post(url, params).then(function(response){

if (!response.data)

return;

 

var hasSelectedValue = false;

field.choices = [];

angular.forEach(response.data.items, function(item){

item.label = item.$$displayValue;

item.value = item.sys_id;

if (field.value == item.value)

hasSelectedValue = true;

field.choices.push(item);

});

 

// If the choice list doesn't contain the current model value, just use the first choice

if (!hasSelectedValue && field.choices.length > 0)

g_form.setValue(field.name, field.choices[0].value, field.choices[0].label);

});

}

 

var pcTimeout;

g_form.$private.events.on('propertyChange', function(type, fieldName, propertyName) {

if (fieldName != field.name)

return;

 

if (propertyName == "optionStack") {

$timeout.cancel(pcTimeout);

pcTimeout = $timeout(function() {

field.choices = applyOptionStack(fieldOptions, field.optionStack);

selectValueOrNone();

}, 35);

}

});

 

setDefaultOptions();

 

if (field.choices) {

setChoiceOptions(field.choices);

}

 

selectValueOrNone();

 

function setDefaultOptions() {

setChoiceOptions([{

value: scope.field.value,

label: scope.field.displayValue || scope.field.placeholder

}]);

}

 

function setChoiceOptions(options) {

// force string values

if (options) {

options.forEach(function(option) {

option.value = String(option.value);

});

}

fieldOptions = options;

scope.options = applyOptionStack(options, scope.field.optionStack);

}

 

function applyOptionStack(options, optionStack) {

if (!optionStack || optionStack.length == 0) {

return options;

}

var newOptions = angular.copy(options);

if (!newOptions) {

newOptions = [];

}

optionStack.forEach(function(item) {

switch (item.operation) {

case 'add':

// validate that duplicate choice label is not being added.

for(var o in newOptions) {

if (newOptions[o].label == item.label)

return;

}

 

var newOption = {

label: item.label,

value: item.value

};

if (typeof item.index === 'undefined') {

newOptions.push(newOption);

} else {

newOptions.splice(item.index, 0, newOption);

}

break;

case 'remove':

 

// normalize comparison to string values

var itemValue = String(item.value);

for (var i = 0, iM = newOptions.length; i < iM; i++) {

var optionValue = String(newOptions[i].value);

if (optionValue !== itemValue) {

continue;

}

newOptions.splice(i, 1);

break;

}

break;

case 'clear':

newOptions = [];

break;

default:

}

});

return newOptions;

}

 

if (angular.isFunction(element.select2)) {

element.select2({

allowClear: false,

width: '100%'

});

 

element.bind("change select2-removed", function(e) {

e.stopImmediatePropagation();

if (e.added) {

var selectedItem = e.added;

g_form.setValue(field.name, selectedItem.id, selectedItem.text);

} else if (e.removed) {

g_form.clearValue(scope.field.name);

}

});

 

// Set the select2 value when the viewValue changes

ngModel.$render = function() {

if (ngModel.$viewValue === "" || ngModel.$viewValue === null)

selectValueOrNone();

 

element.select2('val', ngModel.$viewValue);

};

}

};

 

directive.compile = function() {

return function(scope, element, attrs) {

link.apply(this, arguments);

};

};

 

return $delegate;

}]);

});

/*Script content Ends here */

10) Submit

 


Related Problem: PRB734799

Seen In

There is no data to report.

Fixed In

Jakarta

Associated Community Threads

There is no data to report.

Article Information

Last Updated:2018-08-27 16:47:16
Published:2018-08-27