- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 05-18-2020 08:38 AM
The snRecordPicker directive is a very popular Angular directive to allow flexible reference field behavior in ServicePortal. There have been a couple really influential Community posts about how to use it:
https://community.servicenow.com/community?id=community_blog&sys_id=54bde6a9dbd0dbc01dcaf3231f96193f
I have noticed that while this functionality is very helpful it does not scale very well for performance. Here are some key tips to make your snRecordPicker implementation more performant:
You will need to make your own version of the directive as a ServicePortal widget. It is easier than you might think.
(Thanks Matt Glen for the tip!)
The below steps change the default search behavior to use a Startswith query (much more efficient for MySQL than the default Contains behavior) and also adds a 5 character minimum (configurable) before an auto-complete request will be sent.
1. Create a new "Angular Provider" of type "Directive" and name it in camel-case. (e.g. myRecordPicker, acmeRecordPicker, youGetTheIdea...)
2. Copy paste the entire directive.snRecordPicker code from /scripts/js_includes_sp.jsx into the Client Script field of your new Angular Provider
3. Remove the below outer function call but keep everything else that is inside. With the minor exception of the function; which you must give a name so that "function(" becomes "function myRecordPicker("
angular.module('sn.common.controls').directive('snRecordPicker',
...keep everything in here...
)
4. Now make two minor changes:
- in the "scope" object (around lines 13-27) add a line as follows:
minimumInputLength: '=?',
- in the "config" object (around lines 94-98) add a line as follows (defaults to 3 if nothing set in HTML tag):
minimumInputLength: scope.minimumInputLength ? parseInt(scope.minimumInputLength, 10) : 3,
5. Add the new provider to your widget via the related list to "Angular Providers"
6. In the template (sp_widget HTML Template field or sp_ng_template) where you used to reference "sn-record-picker" you replace that with "my-record-picker" (or the equivalent snake-case name, depending on the name you picked in step #1) - Angular will convert it to the equivalent camel case name you selected in step #1 automatically.
7. Add two new parameters inside the <my-record-picker...> tag in your template, startswith="true" and minimum-input-length="5". It should end up looking something like this:
<my-record-picker
field="c.requestedForUserList"
default-query='c.data.requestedForFilter'
table="'sys_user'"
startswith="true",
minimum-input-length="5",
style="margin-top: 5px;"
display-field="'name'"
display-fields="'user_name,title'"
value-field="'sys_id'"
search-fields="'name,user_name,title'"
page-size="100"
multiple="true">
</my-record-picker>
8. As a final touch, in Orlando the Table REST API supports bypassing the COUNT(*) query. In the "search" method add "&sysparm_no_count=true" to the url as shown below:
var url = '/api/now/table/' + scope.table + '?' + urlTools.encodeURIParameters(queryParams.data) + "&sysparm_no_count=true";
See KB0817996 - Orlando Performance Improvement - Remove Pagination Count
While you're at it, ask your customer to consider raising the value of glide.xmlhttp.ac_wait_time to reduce the frequency of hitting the database with auto-complete requests. Bumping it up to 1000ms doesn't feel too bad, reduces back and forth network wait time and it saves a lot of processing on the database.
- 3,518 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
on trying to save the new myRecordPicker with 45,174 lines [prior to any amends].. reaches 75% and fails. Tried several times.
Any advice.. or perhaps you could post the .xml
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi faro,
Please post the XML of your record picker.
I'm not sure what you mean by "45,174 lines [prior to any amends]". Do you mean that you have manually selected 45k results in the record picker? I don't think that's what you could mean since that would take a really long time because I'm not aware of how to select more than one result at a time with record picker. Do you know something I don't?
Or maybe you mean that, prior to selecting a result, before inputing any characters in the text box, you are paging through a result set with 45k results and you get about 75% the way through the paging (i.e. Are you manually paging through 32k results, 100 at-a-time?! What is your page-size?!). What is your minimum-input-length value?
Anyway, regardless of what you mean, here's some debugging steps that might help:
Open browser developer tools and watch the network tab. Are there any failing requests?
Watch the console tab in developer tools. Are there any relevant javascript errors on the browser?
If neither of these things is happening then maybe this is failing on the server side.
There are tons of ways to debug the server side, but maybe you could start with the Session debugging "Enable All" feature. You might need to trick the UI a bit because not all pages support Session Debugging. The trick is to open a new non-existing URL (blah.do, monkey.do, silly.do) and this UI will support Session Debugging and will output all the stored debugging information since the last time a page was loaded that does support Session Debugging.
Regards,
Please mark 👍 if Helpful
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Here's the XML for my custom Record Picker directive.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I've added an Idea in the Idea Portal. Please vote for it if you think making these improvements in the core product would be a helpful enhancement!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for this!
I changed the default value to null instead of 3. That way if I don't specify the minimum-input-length or set it to "0" then it turns this feature off and works as usual. I added some other changes and wanted to use this across multiple controls but some I wanted the minimum search on and some I did not. This gives me the best of both worlds.
minimumInputLength: scope.minimumInputLength ? parseInt(scope.minimumInputLength, 10) : null