Picklists - tsgrp/HPI GitHub Wiki
If you're looking for instructions on how to configure existing picklists in HPI, click here. If you'd like to configure new picklists in HPI, the following sections overview the different types of picklists available in HPI.
In the HPI Admin's Picklist Config section, adminstrators can configure "Simple" picklists. A simple picklist is a list of labels and values managed directly in the HPI admin. Each picklist can be ordered at will by the HPI administrator and can have a default value.
Note - HPI Static picklists should not be used for picklists that have many (20+) rows or that can cascade from other picklists.
OpenContent Picklists are configured in the project-bean-config.xml
. Note that in many oc projects, this file imports a separate project-oc-picklists.xml
. While not necessary, doing it this way allows picklists to be configured separately from the rest of the project config, which may be cleaner if you have a large project-bean-config.xml
.
All picklists are configured using a Spring MapFactoryBean
, as follows below. Note that the bean id, class, and property name must match this for your picklist bean to be picked up:
<bean id="ProjectPicklists" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
</map>
</property>
</bean>
Each map entry describes an OC picklist, using the following syntax:
<entry key="picklistKey" value="picklistValue"/>
The key must be unique across all OC picklists (including other picklist types such as Simple Picklists). The text entered for the picklist value will depend on the type of OC Picklist you're trying to create.
For circumstances where you want picklists to come from two different data sources - such as a SQL Database and Alfresco - there is a Deferred Picklist implementation. When using the Deferred Picklist implementation, you create the Picklist beans for the other implementations as normal, but make the Picklist implementation have those beans mapped to a key. This key then must be prefixed to the actual picklist query, surrounded by the '#' symbol; if a picklist is not prefixed, errors will occur attempting to use it. An example is below:
<entry key="areas" value="#JDBC#SELECT name FROM areas;" />
<entry key="regions" value="#ALF#lucene|tsg:documentNumber|TYPE:tsg\:document|tsg:documentNumber"/>
OC's picklist parsing can interpret static picklists successfully. Current implementation supports a mixture of values and labels. Simply separate values and labels with a ",", and separate separate picklist entries (made up of just a value, or of a value and a label) with a ";". If you want your picklist label or value to contain a "," or a ";", escape a character with "\," or "\;".
Note: It is assumed that the string before the comma is the label and the string following the comma is the value. ("Item_Label,Item_Value;Item_Label_2,Item_Value_2")
Some examples of valid static picklist configurations:
"Indiana,IN;Illinois,IL;Ohio,OH"
"Apples;Oranges;Bananas"
"Short;ReeeeeaaaaaalllllllyyyyyLooooonnnggggg,RealLong"
"Larry\\, Moe\\, Curly,threeStooges;Lana\\, Archer\\, Cyril,archerCharacters"
A Documentum OC Picklist runs a DQL query. Basic set-up for all queries should be something like this:
select value_column, label_column from your_type
Or:
select value_and_label_column from dm_dbo.picklist_table
Your where clause, for a cascading query, will need to be something like this:
select value_and_label_column from dm_dbo.picklist_table where attr_one='$attrOneVal$'
In this case, attrOneVal
must be present on the form in order for this query to cascade properly. It is also important that these keys are unique within each query. For example, you couldn't have a second
A few things to note when setting up your query:
- The value must be the first column/attribute of the query to come back, i.e. the first thing listed in the select clause of the query.
- If there is only one column/attribute returned in the query, the values in that column/attribute will be used for each picklist entry's value and label.
- If there are more than one column/attribute returned, only the first two will be used. The first column/attribute will be used for the value, and the second will be used for the label.
Here is an example ProjectPicklists bean:
<bean id="ProjectPicklists" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="picklist_one" value="select value_column, label_column from dm_dbo.picklist_one"/>
<entry key="one_column_picklist" value="select value_column from dm_dbo.one_column_picklist"/>
<entry key="cascading_picklist" value="select value_column, label_column from dm_dbo.picklist_one where my_attr='$my_attr_val$'"/>
<entry key="double_cascading_picklist" value="select value_column, label_column from dm_dbo.picklist_one where my_attr='$my_attr_val$' and num_attr < $num_attr_val$"/>
</map>
</property>
</bean>
There are a number of ways to setup OC picklists in Alfresco:
Basic set-up for all entries should be in the following format:
lucene|labelColumn,valueColumn|query|sortAttr
Or, to create a label by concatenating multiple attributes:
lucene|labelAttr0+' '+labelAttr1+' '+labelAttr2,valueColumn|query|sortAttr
where the quotes can include any string to concatenate between attributes.
In the above setup there are four parts:
- The language to use for searching - currently only lucene queries are supported.
- The label and value columns to use. The value column is optional.
- The actual query to execute.
- The attribute to sort the returned results by (optional).
Here is an example OC picklist using lucene:
<bean id="ProjectPicklists" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<!-- selects cm:name (label and value) for all objects of type cm:content that contain the phrase 'banana' in their name. -->
<entry key="oneColumnPicklist" value="lucene|cm:name|TYPE:cm\:content AND @cm\:name:'banana'"/>
<!-- selects cm:name (label) and sys:node-uuid (value) for all objects of type cm:content that contain the phrase 'banana' in their name. -->
<entry key="twoColumnPicklist" value="lucene|cm:name,sys:node-uuid|TYPE:cm\:content AND @cm\:name:'banana'"/>
<!-- selects cm:name (label and value) for all objects of type cm:content that contain the letters 'ban' followed by anything else in their name. -->
<entry key="wildCardCharPicklist" value="lucene|cm:name|TYPE:cm\:content AND @cm\:name:ban*"/>
<!-- selects cm:name (label and value) for all objects of type cm:content that contain the phrase 'banana' in their name and sorts the results by cm:modified. -->
<entry key="sortPicklist" value="lucene|cm:name,sys:node-uuid|TYPE:cm\:content AND @cm\:name:'banana'|cm:modified"/>
<!-- selects cm:firstName and cm:lastName as label and cm:userName as value for all objects of type cm:person sorted by cm:lastName -->
<entry key="concatenatedPicklist" value="lucene|cm:firstName+' '+cm:lastName,cm:userName|TYPE:cm\:person|cm:lastName"/>
<!-- Example Cascading picklist -->
<entry key="policyNumberForClaim" value="lucene|insuranceDemo:policyNumber|TYPE:insuranceDemo\:claimsFolder AND insuranceDemo\:claimNumber:'$insuranceDemo_claimNumber$'|insuranceDemo:policyNumber" />
</map>
</property>
</bean>
As with Documentum OC picklists above, cascading queries are configured using $prop_oc_name$
syntax in the picklist value.
Check out Lucene Alfresco syntax page for more detailed information on writing queries. The Apache Lucene Syntax page is also helpful, but note there may be differences as the parser it uses may be different.
Picklists with a datalist source may be configured if the Alfresco and Share repositories have the TSG Cascading Value Assistance Alfresco and Share AMPs installed. This configuration option is useful because this allows business users to maintain picklist values without IT involvement.
Steps to create the datalist:
- Once the TSG Datalist AMPs have been installed navigate to Share. Navigate to a site and open up the "Data Lists" tab. (This might need to be configured using the site settings tool located in the upper right corner).
- In the upper left hand corner click the "New List" button.
- Select one of the Value Assistance lists and give it a title then click save.
- Add as many items as you would like.
After a datalist has been added in Alfresco or Share, use the following syntax to use the values as a picklist:
datalist|datalistName|labelColumn,valueColumn|cascadingQuery
The above value has four parts:
-
datalist
- tells OC that this picklist is driving from a datalist - The name of the datalist
- The label and value columns to use. This section is optional. If omitted, OC will return the label and value from the first level of the datalist.
- Cascading query to use for multi-level datalists. This section is optional, see below for details.
For non-cascading datalist picklists, OC will automatically look for the label and value columns and return them sorted by the label column. For example, say we have a datalist named 'Business Departments', the picklist entry config is as simple as:
<entry key="businessDepartments" value="datalist|Business Departments"/>
When using a cascading picklist against a datalist, using the above syntax will populate the picklist with the level 1 values and labels. If you want to use the other columns of the data list, use a lucene query to get the desired result.
For example, say we change the above datalist to be a cascading list from a 'region' column. Region is the level 1 value, and business department is the level 2 value. Your picklists would then look like this:
<entry key="regions" value="datalist|Business Departments"/>
<entry key="businessDepartments" value="datalist|Business Departments|cva:2LevelLabel,cva:2LevelValue|TYPE:cva\:2LevelValueAssistanceListItem AND @cva\:1LevelValue:"$myApp_region$""/>
In the above query, the $ prefixed tokens should refer to the OC Name
of the attribute you're cascading from.
A usersInGroup
picklist was created to allow querying users in a given Alfresco group. The syntax is simple:
usersInGroup|groupName|query|format
For example, to get users in the Wizard Contributors group, you could define an OC picklist like the following:
<entry key="wizardContributors" value="usersInGroup|GROUP_wizard_contributors|$query$|$firstName$ $lastName$"/>
If you want to list all users in a group and ignore any queries(in other words, not have an async picklist), you can simply omit the last 2 parameters, as follows:
<entry key="wizardContributors" value="usersInGroup|GROUP_wizard_contributors"/>
Note that the currently supported tokens are
As of this writing (May 2016), there's no control over the picklist label/value or sorting. The defaults are:
- Label =
FirstName LastName
- Value =
userId
- Sorting = however
serviceRegistry.getAuthorityService().getContainedAuthorities()
returns users - Depth - users in the given group and any subgroup are returned
In the future, we could expand the syntax of the picklist to allow the following configurations:
- What label column to use (or combination of columns - like
firstName + " " + lastName
as in lucene picklists) - What value column to use
- What column to sort on
- Whether or not to get users in the immediate group only or include subgroups
When running OC for HBase or a Solr Portal, you can configure picklists in a manner relatively similar to Alfresco. The key difference being that, while in Alfresco we use the Lucene Query Language, when running in HBase or directly on Solr, we simply use Solr's base query syntax. A few examples follow, but Solr's own documentation is more thorough.
Basic set-up for all entries should be in the following format:
query|sortAttr
In the above setup there are two parts:
- The actual query to execute.
- The attribute to sort the returned results by (optional).
Here are two examples OC picklist using Solr:
<entry key="uid" value="query|aw_pageSetName_s:"Change Request"|aw_uid_s" />
<entry key="formName" value="distinctattribute|cm_name_s|$query$*|Change Request" />
The second uses a special 'distinct' query that returns all distinct values for a given attribute.
We can also add static values to these picklists and then the results of the query will be added on the list. For example:
<entry key="tags" value="Banana;Apple;query|$onTrac_s$ AND objectType_s:Document|sitlaTags_ss" />
In the above example - the first two elements are static and then the results of the query will be added on to the static list.
WebService picklists get their values by making a GET request to a URL. For example, this could be an Alfresco webscript, and OpenContent endpoint, or anything else. The web service should return a JSON string containing the picklist items. HPI will interpret the keys as the item labels, and the value as the item values. An example JSON could be:
Example WebService Response for a Regions Picklist
{
"North":"N",
"South":"S",
"East":"E",
"West":"W"
}
Note that as with all other network communication, this web service must abide by the Same-origin policy. This means that the webservice must look (to the browser) like it's on the same server and port as HPI. Since OpenContent must be configured this way for general HPI installation, if the picklist is implemented in OpenContent nothing additional needs to be done. If your web service is installed on a separate server or port you must proxy the request, typically via Apache. See the HPI Installation Guide for additional information on how do do this.
NOTE - DataDictionary picklists are reserved for future use. See https://github.com/tsgrp/hpi/issues/752.
DataDictionary picklists will get their values from the underlying data model.
- If it hasn't been created yet, you will need to create your picklist config by clicking 'Create Config'. The name isn't important, but is typically set to
default
. - In the Main Configuration Section, enter the name for your new picklist. This name is not visible to the user and must be unique across all picklists in HPI. This name can match the name of your OC picklist, however (see above).
- In the dropdown, choose the type of picklist you would like to create.
- Simple Picklist - your picklist will be added immediately to the list of picklists. Click it to begin configuring your picklist.
- OpenContent Picklist - you will now see a dropdown appear with the name of the keys in your 'ProjectPicklists' bean you created (see above). Select the picklist and click 'Add'.
- Select a picklist in the list and you can see all the possible values for the picklist and you can choose a value in the list to be the default for the input that the picklist is used for. Delete the picklist by clicking the x next to the name of the picklist (below the list of picklists) after selecting it.
- When finished configuring your picklists, click 'Save Config' to save the changes.
Once your picklist is created, a select box allows you to choose the Picklist Load Type:
- Normal - When the view is rendered, the picklist's values will be queries. While this ensures the most up-to-date information, very large picklists or many picklists on a single view can cause the application to slow down.
- Async - Picklist values are not queried until the user enters three characters OR the dropdown arrow is clicked (see below for more information about the dropdown arrow). Values are filtered on the server side, so your picklist query needs to account for this. Async picklists are recommended for very large picklists or cases where you have a lot of picklists on a view at once. See below for more information about asych picklists.
-
Cache at Login - Picklist values will be cached at login and will remain in browser memory until the user logs out. This means that cascading picklists cannot be cached. Large picklists should not use this setting.
- Note: see https://github.com/tsgrp/HPI/issues/1057
- In Form Config, select a form and click/add the Object Type you would like to work on.
- Select/add the attribute you would like to tie to a picklist. Change the control type to a type that supports picklists (ex: DropDown, AutoComplete, ReadioButton, Checkbox).
- Click the options dropdown and select the desired picklist.
- In the options dropdown, click the 'cascading' option. A 'Depends On' dropdown will display the type's attributes. Choose the attribute(s) that this field should cascade from.
- When a user attempts to fill out a form with a cascading picklist, the 'cascaded to' field will only be editable if all the attributes that the field depends on have values.
Since the user is forced to type characters into the Autocomplete box before the query is fired, we want to filter the results on the server side based on the value typed in. A special token called query
is passed when an Async picklist fires. This token should be used in the query, similar to a cascading query. For example:
<entry key="vendors" value="select vendor_name from dm_dbo.vendors where vendor_name like '$query$%'"/>
In the above query, we are filtering vendors with the name that starts with whatever the user has typed. We can easily change this to a contains search by updating the query to: ... vendor name like '%$query$%'
.
By default, the Autocomplete field that loads an async picklist will not have a dropdown arrow that allows the user to load all values. HPI defaults this way since typically an async picklist has a lot of values (10,000+). In this case, there is never a time where you want the user to load all values in a dropdown since it would be a) slow, and b) not all that helpful.
However, there are some cases where you would want the dropdown arrow. One example would be a form in HPI that has many medium-size queries. Rather than having all of them fire on page load, or cached in memory upon login, it may be better to make these async picklists. In this case, it's not harmful or user-unfriendly to load all values. To enable this, check the 'Allow Dropdown' checkbox in the Options section. Note that this checkbox only affects the control if it is an Autocomplete.
It is also worth noting that for performance reasons, when 'Allow Dropdown' is enabled, we only load the async picklist the first time the dropdown arrow is clicked.
A growable picklist should be used when you want to allow the user to enter values that are not already in the picklist. Growable picklists are only available for the 'Autocomplete' control type in HPI. Simply check the 'Growable' checkbox in the Options dropdown to allow users to enter arbitrary values.
When using growable picklists, keep in mind that your query must account for the new values entered in the field. For this reason, you'd only use the growable option with OpenContent picklists. For example, a growable picklist entry may look like:
Documentum
<entry key="regions" value="select distinct region from project_folder"/>
Alfresco
<entry key="regions" value="lucene|myApp:region|TYPE:myApp\:projectFolder|myApp:region"/>
In either case above, we're getting the distinct region
value from all project folders in the system. If an arbitrary value is entered, it will be retrieved in the next query.
From a governance standpoint, be careful with growable picklists as typos and other human errors can cause the list to grow unwieldy.