Hide widgets dependent on 'onchange' value or custom button

walshy
Giga Expert

I have googled my way and searched through the community but I cannot work out how to do the following. 

I have 4 set lists that are 4 widgets (editable table) on a gig form.

I want to have those 4 widgets hidden and only show up when the number of sets is chosen. That answer was going to be in choice field on the form, however I think onchange doesnt work as a UI in the portal. The obvious thing here is if 2 sets is selected, then 2 set lists show up.

I thought about using a button and having the end user click the number of lists they want and then the set lists show that are required.

I thought combining the idea from here: https://serviceportal.io/create-custom-action-buttons-service-portal/

with the idea from here: https://community.servicenow.com/community?id=community_blog&sys_id=e60eea2ddbd0dbc01dcaf3231f961972

would work, but doing that kinda makes my brain explode.  

Below is how it currently looks

find_real_file.pngYou can see why I'd prefer the sets required to be the choice list, it doesn't screw up the page as the buttons do, but hopefully you all get the idea and can point me in the right direction, or tell me I just have to be resigned to having the 4 set lists viewable at all times. 

Thanks for your suggestions. 

 

 

1 ACCEPTED SOLUTION

So guess what happened Josh, the end users decided they didnt want buttons but wanted all 4 set lists to show, plus a 5th list with all of the songs in it. 

It did simplify things for me, but not the full result we were looking at. 

find_real_file.png

The end users are happy, so I must say thank you for all your help!

View solution in original post

9 REPLIES 9

Josh Virelli
Tera Guru

Hi Walshy,

I would use events and broadcast them from your "How many sets" widget to the the "Set list" widgets. You can read about events and broadcasting events here: Using Events to Communicate Between Widgets.

Basically, each one of your buttons, on ng-click, will broadcast an event, let say it's called "updateSetLists". You can also pass along a string or object as a second parameter. I think we just need a string here, being the number of set lists we'd like to show: 1,2,3, or 4.

And then on your Set list widgets, will set up a listener for the event, and update a data.variable that will tell the widget to hide and show. Instead of making 4 separate widgets for each Set list, we should instead, set the event listener as an option in the Widget Options Schema. Then you can configure the parameters outside the widget, and make it reusable and modular.

Here's an examples:

THIS GOES ON THE SET LIST BUTTON WIDGET

HTML

<button class="btn btn-default" ng-click="c.clickButton('1')">1 Set list</button>
<button class="btn btn-default" ng-click="c.clickButton('2')">2 Set lists</button>
<button class="btn btn-default" ng-click="c.clickButton('3')">3 Set lists</button>
<button class="btn btn-default" ng-click="c.clickButton('4')">4 Set lists</button>

CLIENT SCRIPT

function($rootScope) {
	var c = this;
	c.clickButton = function(setListNumber) {
		$rootScope.$broadcast('updateSetLists', setListNumber);
	}
}

 

THIS GOES ON THE SET LISTS EDITABLE TABLE WIDGET

If you're using an out-of-the-box widget for the "editable table" or "Set list" widgets you have displayed above, please clone that widget so that you can edit it. After you've cloned, we are going to add an option to the Widget Option Schema, and then configure it in each of the widgets in the "Instance Options". You can get to these by control+Left clicking (Mac) / CTRL+right-click (PC) on the widget in the Service Portal 

We need to add an option that contains the parameter. Set the name to "parameter" and type as string.

Once you've added the options, it's time to edit our widget.

HTML

You'll want to update it so the top <div> is something like <div ng-if="data.eventTrue">

CLIENT CONTROLLER

We'll handle the processing of the event and setting that data.eventTrue to true or false. Not sure what already exists in the client controller, just make sure you add $rootScope to the list of parameters in the function() at the top. and then add the $rootScope.$on part below. and var c = this, if doesn't already exist.

function($rootScope) {
  var c = this;
  $rootScope.$on('updateSetLists', function(event,setListNumber) {
		if(setListNumber >= c.options.parameter){
c.data.showWidget = true;
}else{
c.data.showWidget = false;
}
  });
}

SERVER SCRIPT

Just add this line somewhere in the server script:

data.showWidget = false;

 

This is how I would tackle it, if you have questions, ask them here and I'll do my best to respond. Not sure what your level of familiarity with Service Portal is, so I tried to include as much as a I could to help.

Thanks,

Josh

Hi Josh, 

This was awesome, very helpful indeed. I actually get the logic now, so thank you for that. However I am having difficulties getting the broadcast from the sets required button to be heard by the 4 set list widgets. 

I started writing out a long and complicated email but started again. 

Can you please glance over the below code for me. 

BUTTON WIDGET - sets required

HTML

<div class="panel panel-default">
 <div class="panel-heading">Sets Required</div>
 <div class="panel-body">
   <button class="btn btn-success" ng-click="c.clickButton('1')">Set list 1</button>
   <button class="btn btn-success" ng-click="c.clickButton('3')">Set list 3</button>
   <button class="btn btn-success" ng-click="c.clickButton('2')">Set list 2</button>
   <button class="btn btn-success" ng-click="c.clickButton('4')">Set list 4</button>
 </div>
 </div>
<div>

 

CLIENT 

function($rootScope) {
var c = this;
c.clickButton = function(setListNumber) {
$rootScope.$broadcast('updateSetLists', setListNumber);
}
}

There is no need for a server script for this right? 

EDITABLE TABLE - set list (this has been cloned so I can edit it)

HTML

<div ng-if="data.eventTrue">
  <div class="alert alert-danger" ng-if="data.invalid_table">
    ${Table not defined} '{{data.table_label}}'
  </div>
  <sp-widget ng-if="data.dataTableWidget" widget="data.dataTableWidget"></sp-widget>
</div>

 

CLIENT

function ($rootScope, $scope, spUtil, $location, spAriaFocusManager) {
	var c = this;
	 $rootScope.$on('updateSetLists', function(event,setListNumber) {
		if(setListNumber >= c.options.parameter){
c.data.showWidget = true;
}else{
c.data.showWidget = false;
}
  });
	
	$scope.$on('data_table.click', function(e, parms){
		var p = $scope.data.page_id || 'form';
		var s = {id: p, table: parms.table, sys_id: parms.sys_id, view: 'sp'};
		var newURL = $location.search(s);
		
		spAriaFocusManager.navigateToLink(newURL.url());
			
	});

}

SERVER

(function(){
	/*  "use strict"; - linter issues */
	// populate the 'data' object
	var sp_page = $sp.getValue('sp_page');
	var pageGR = new GlideRecord('sp_page');
	pageGR.get(sp_page);
	data.showWidget = false; //TO HIDE SET LIST WIDGETS ON PAGE LOAD
	data.page_id = pageGR.id.getDisplayValue();
	$sp.getValues(data);
	if (data.field_list) {
		data.fields_array = data.field_list.split(',');
	} else {
		data.field_list = $sp.getListColumns(data.table);
	}

	if (input) {
		data.p = input.p;
		data.o = input.o;
		data.d = input.d;
		data.q = input.q;
	}
	data.p = data.p || 1;
	data.o = data.o || $sp.getValue('order_by');
	data.d = data.d || $sp.getValue('order_direction');

	data.page_index = (data.p - 1);
	data.window_size = $sp.getValue('maximum_entries') || 10;
	data.window_start  = (data.page_index * data.window_size);
	data.window_end = (((data.page_index + 1) * data.window_size));
	data.filter = $sp.getValue("filter");
	
	var gr = new GlideRecordSecure(data.table);
	if (!gr.isValid()) {
		data.invalid_table = true;
		data.table_label = data.table;
		return;
	}
	data.table_label = gr.getLabel();

	var widgetParams = {
		table: data.table,
		fields: data.field_list,
		o: data.o,
		d: data.d,
		filter: data.filter,
		window_size: data.window_size,
		view: 'sp',
		title: options.title,
		show_breadcrumbs: false
	};
	data.dataTableWidget = $sp.getWidget('editable-data-table', widgetParams);
})();

I created the schema variable as suggested on the Editable table widget, so each widget has a number in the variable corresponding to the table name, 1, 2, 3, or 4. I named it parameter at the schema level.

find_real_file.png

So as far as I can tell the buttons broadcast fine, but the controller on the editable table is not hearing the broadcast and I know it will be how I have the code in the client, but I dont know how to 'mix' the required code for the widget and then the new code for the control of show/hide. 

I feel like I am so close but I am missing a small bit. 

Also I have found when I make the changes in the controller of the set list widget the data vanishes, this is why I think it is my controller in that widget that is the issue.

find_real_file.png

Suggestions? 

Also, thank you so much for the help. 

 

Hi Walshy,

I got this working in a dev instance. The two things you missed were replacing the c.options.parameter with the name of your parameter. If you left it by default it would be "set_number", so line 4 in your Client Controller in the Table widget should be 

if(setListNumber >= c.options.set_number){

And line 1 in the HTML of that same widget, change the ng-if statement to look for the data.showWidget value:

<div ng-if="data.showWidget">

Legend,


Thanks Josh, I have the sets showing up now if the buttons are clicked, the form loads with no set lists so thank you for your help. 

It was the html where I was going wrong, I was lazy and named the parameter parameter, but I understood what was going there after you explained it. 

I will probably go and rename it now.... 

Also this is related but a little different, when I save the page the set list is on, and then re open it, the set lists are not saving on the form, they vanish again. 

Should I put in an "if" statement somewhere to ensure they stay viewable, because all of this happens at the controller level when the form reloads the set list widgets wont know what their status is as the data will be cleared if I have my logic correct? 

Once again thank you.