sn-record-picker Helper, Part II

“If I had eight hours to chop down a tree, I’d spend six hours sharpening my ax.”
Abraham Lincoln

Now that we have all of the form fields and controls laid out on the page, the next order of business is to build the function that will use the form input to create the desired sn-record-picker. We have already specified an ng-submit function on the form, so all we have to do at this point is to actually create that function in the client-side script. This function is actually pretty vanilla stuff, and just takes the data entered on the screen and stitches it all together to form the resulting sn-record-picker tag.

$scope.createPicker = function() {
	var picker = '<sn-record-picker\n    table="' + "'";
	picker += c.data.table.value + "'";
	picker += '"\n    field="';
	picker += c.data.field;
	if (c.data.filter) {
		picker += '"\n    default-query="' + "'";
		picker += c.data.filter + "'";
	}
	picker += '"\n    display-field="' + "'";
	picker += c.data.displayField.value + "'";
	if (c.data.displayFields.value) {
		picker += '"\n    display-fields="' + "'";
		picker += c.data.displayFields.value + "'";
	}
	if (c.data.searchFields.value) {
		picker += '"\n    search-fields="' + "'";
		picker += c.data.searchFields.value + "'";
	}
	if (c.data.valueField.value) {
		picker += '"\n    value-field="' + "'";
		picker += c.data.valueField.value + "'";
	}
	if (c.data.multiple) {
		picker += '"\n    multiple="true"';
	}
	if (c.data.placeholder) {
		picker += '"\n    page-size="';
		picker += c.data.pageSize;
	}
	if (c.data.pageSize) {
		picker += '"\n    placeholder="';
		picker += c.data.placeholder;
	}
	c.data.generated = picker + '">\n</sn-record-picker>';
	c.data.ready = true;
	return false;
};

One of the last few things that happens in that script is to set c.data.ready to true. I set that variable up to control whether or not the rendered tag should appear on the screen. Altering any of the fields on the screen sets it to false, which hides the text box containing the generated code until you click on the button again. To make that work, I just added an ng-show to the enclosing DIV:

<div class="col-sm-12" ng-show="c.data.ready">
  <snh-form-field
    snh-model="c.data.generated"
    snh-name="generated"
    snh-label="Your sn-record-picker:"
    snh-type="textarea">
  </snh-form-field>
  <p><a href="javascript:void(0);" onclick="copyToClipboard();">Copy to clipboard</a></p>
</div>

The other thing that you will notice inside of that DIV is the Copy to clipboard link. That one uses a standard onclick rather than an ng-click, because that’s a DOM operation, which is outside the scope of the AngularJS controller. The referenced script, along with another DOM script that I use to set the height of that textarea, are placed in a script tag with the HTML.

<script>
function fixTextareaHeight() {
	var elem = document.getElementById('generated');
    elem.style.height = (elem.scrollHeight + 10)  + 'px';
}
function copyToClipboard() {
	var elem = document.getElementById('generated');
	elem.select();
	elem.setSelectionRange(0, 99999)
	document.execCommand('copy');
	alert("The following code was copied to the clipboard:\n\n" + elem.value);
}
</script>

Clicking on that Copy to clipboard link copies the code to the clipboard and also throws up an alert message to let you know what was copied.

Alert message after copying the code to the clipboard

The next thing on my list was to actually place the code on the page so that you could see it working. I tried a number of things to get that to work, including ng-bind, ng-bind-html, ng-bind-html-compile, and sc-bind-html-compile, but I could never get any of that to work, so I ultimately gave up on trying to use the actual generated code, and did the next best thing, which was to just set up a picker of my own using the selected options.

        <div class="col-sm-12" ng-show="c.data.ready">
          <snh-form-field
            snh-model="c.data.liveExample"
            snh-name="liveExample"
            snh-label="Live Example"
            snh-type="reference"
            snh-change="optionSelected()"
            placeholder="{{c.data.placeholder}}"
            table="c.data.table.value"
            display-field="c.data.displayField.value"
            display-fields="c.data.displayFields.value"
            value-field="c.data.valueField.value"
            search-fields="c.data.searchFields.value"
            default-query="c.data.filter">
          </snh-form-field>
        </div>

This approach allowed me to add a modal pop-up that showed the value of the item selected.

Modal pop-up indicating option selected

The code to make that happen is in the client-side controller:

$scope.optionSelected = function() {
	spModal.open({
		title: 'Selected Option',
		message: '<p>You selected  "<b>' + c.data.liveExample.value + '</b>"</p>',
		buttons: [
			{label: 'Close', primary: true}
		],
		size: 'sm'
	});
};

One other thing that I should mention is that the snh-form-field directive that I used in this example is not same as the last version that I had published. To support the multiple=true/false option, I needed a checkbox, and for some reason, I never included that in the list of many, many field types that included in that directive. I also had to tweak a few other things here and there, so it’s no longer the same. I should really release that separately in a future installment, but for now, I will just bundle it with everything else so that this will all work as intended.

I wrapped the whole thing in an snh-panel, just to provide the means to add some documentation on the sn-record-picker tag. I had visions of gathering up all of the documentation that I could find and assembling it all into a comprehensive help screen document, but that never happened. Still, the possibility is there with the integrated help infrastructure.

Pop-up widget help screen

I also added a sidebar menu item so that I could easily get to it within the main UI. It may be a Service Portal Widget under the hood, but it doesn’t really belong on the Service Portal. It’s a development tool, so I added the menu item so that it could live with all of the other development tools in the primary UI. If you want to take it for a spin yourself, here is an Update Set.

Update: There is a better (corrected) version here.

Reference Type System Properties

“To succeed in life, you need two things: ignorance and confidence.”
— Mark Twain

Whenever I create a ServiceNow application, I invariably end up setting up one or more System Properties to control the behavior of the app, set up options for the app, or allow the app to function differently in different environments such as Test or Production. Recently, I wanted to create a property that would be selected from a table, or in ServiceNow terms, a Reference property. Unfortunately, when I scanned the list of available property types, Reference was not on the list.

Available System Property Types

Well, not to worry. Choice Lists are easily modified, so I went to sys_properties.list, then Configure -> Table, and clicked on the Type column to bring up the Dictionary Entry. From there, I clicked on the Choices (13) tab and then clicked on the New button to create a new choice. I typed the word reference into both the Label and Value fields and then clicked on the Submit button to save the new choice. Voila! Now my instance supports System Properties of Type Reference:

New Reference Type added to the Choice List

Of course, that was the easy part … there’s still much to do. First of all, we are going to need to add another field so that we can capture the Table we will be using for the Reference. And now that I am looking at that form, there are a couple of things that are irritating my sense of The Way Things Ought To Be that I am just going to have to clean up while I’m in there. For one, the need for the Choices field is dependent on the value of the Type field, so the Type field should come first. Additionally, the Choices field shouldn’t even appear on the form if the Type is not Choice List. The new Table field, which itself should be a Reference to the Table table, should only appear if the Type is Reference. If the Type is not Choice List and the Type is not Reference, then the very next field should be Value. Let’s see if we can’t clean all of that up next.

To begin, we can add the new column to the sys_properties table right from the form itself using the hamburger menu:

Updating the Table from the Form

This will take us to the list of columns where we can click on the New button to create a new column on the table. Select Reference as the Type, enter Table as the Label and then go down to the Reference Specification tab and select Table as the Reference.

New Table Column

Saving the new column will return us to the Table specification, and clicking on the return (<) icon up in the left corner will get us back to the form where we can use the hamburger menu to select Configure -> Form Layout to move things around. Doesn’t that look better!

Rearranged System Property fields

Now, with a little UI Policy magic, we can hide both the original Choices and the new Table unless the appropriate Type has been selected. Back again to the hamburger menu where we can select Configure -> UI Policies to implement the desired changes. We’ll need to add two new policies, one for the Choices field and one for the Table field. You first have to create the policies and save them, then you can go back in and add the actions to take when the conditions are met. The condition on the first will be Type = choice list and the condition on the second will be Type = reference. Be sure the check the Reverse if false option, as we will want these policies to toggle between the true and false conditions.

Once the policies have been created, you can go back in and add the appropriate action. On the Type = choice list policy, the action will be to make the field Choices visible. On the Type = reference policy, the action will be to make the new field Table visible. Because you selected the Reverse if false option on both policies, when the the Type is not set to the specified value, the result will be that the relevant field will no longer be present on the screen.

System Property form with neither Choice List nor Reference selected

There are still a couple of more things that we could do here to make this complete, but at this point I don’t really have a pressing need for either, so I am just going to let those go for now. The first would be a potential filter for the reference fields, as there are occasions where you don’t want the user choosing from the entire contents of the table. That would basically be handled like the Table field itself, appearing on the form only when reference was selected as the Type.

The other thing that could be done at this point would be to alter the Value field to behave in accordance with the selected Type. This would seen like the appropriate thing to do, but out of the box, the open text input box does not transition to a selection of choices when you select choice list as the Type. I think the main reason that it doesn’t do that is because this is not really the place where property values are set. Properties are defined on this form, but there is another form that is generally used to set the value. We’ll tackle that form next time, as that work will be a job in and of itself.