Today, we are going to take a detailed look at a common request we often get (during presales, support, or consulting) that can be stated as follow: “In the default JSF UI, at creation or modification time, given the value chosen by the user in suggestion widget #1, I want to display a specific list of values in suggestion widget #2”.
Something like:
In this screenshot, depending on the chosen type for a claim (yes, this is Case Management example), the subtype widget displays different choices: Exactly what we need.
Now, maybe you are wondering “Cool. But is it possible to solve such a big challenge with just Nuxeo Studio?”. And my answer is: “Yes!”. “Yes, you can use Studio for this”. Because here is a fact: Nuxeo Studio is the best configuration tool for the Nuxeo Platform you can find in this universe. I can’t tell for other universes - never been there - but I can tell for our own: Nuxeo Studio rocks! And to follow a kind of tradition, here is the playlist to listen to while reading the blog. First one gives me goose bumps.
Let’s do it. As usual, it will take way longer to explain than to actually perform this task. On the other hand, it allows us to spend more time together, which is priceless to me.
The main points here are: First, we use suggestion widgets. Second, we use suggestion widgets (yes, I know: Just said that. Wait for the next couple of words) bound to a vocabulary. We already had two similar tutorials about binding two suggestion widgets. One that handles suggestion widgets bound to Documents, and another one for Users & Groups. We can say that this blog closes the topic.
The main principles are the same:
1. Have two Suggestion widgets.
2. Get, at runtime (in the web inspector of your browser) the DOM ID of the first one
3. In the second one, inject some inline JavaScript and add custom properties.
4. Add a custom operation that will return the values you want.
So, let’s say we have a Claim
document, with its claim:type
and claim:subtype
fields. We also have four vocabularies. With a little trick here, used later: Make sure the Id
of the subtypes match the Id of each entry in ClaimType
:
It is not a requirement for the configuration to work, it just makes the operation which dynamically fetches the correct vocabulary a bit easier to write (see below).
Now, in a Creation and/or an Edit layout, you already have drag-dropped the two fields, using suggestion widgets. Claim:kind
is bound to the ClaimType
vocabulary, and you also bind claim:subtype
to a vocabulary. This is required by the suggestion widget, just select any vocabulary.
Then, follow one of the previous tutorials to get the DOM ID of the first (claim:type
) widget. Notice that you actually don’t need the full DOM ID, just enough to find it with jQuery, and usually, the piece of ID you need is “fieldname_select2”. In our example: it’s “type_select2”.
We can, at last, move to the configuration of the connection between the two widgets. Everything is done in the second one. Subtype in our example. The Nuxeo Platform has everything we need to exchange data, even in the context of a Creation/Edit layout. This is because a suggestion widget accepts inline JavaScript (where we can inject custom values) and also runs an operation to fetch the values. This operation can also be overridden.
This is precisely what we are going to add to the Subtype suggestion widget:
1. Inject Inline JavaScript that will store the value selected for claim:type
,
2. Bind the widget to a custom operation, which gets this value and acts accordingly
The JavaScript to inject is the following (copy/paste/adapt in the Inline Javascript property of the widget):
bash function getSelectedClaimType(temp, params,query){ var firstSelectionId = "input[id$='type_select2']"; temp.claimType = jQuery(firstSelectionId).attr("value"); //console.log(JSON.stringify(temp)); return temp; }
The most important part here is to return the temp
parameter. This is what is expected by The Nuxeo Platform, and this is what is passed to your operation, as Operation Parameters. Here, we add the claimType
property (line #3), and fill it with the value of the Type
suggestion. As screenshots are why I live for, here is another one:
We can now add custom properties to the widget, and we need to add two of them. Make sure to enter the keys exactly as the Nuxeo Platform expects:
additionalOperationParameters
and operationId
. In the first one, the value is the name of the function you declared in the inline JavaScript, here getSelectedClaimType
. In the second one, you put the name of the operation that will be used to fetch the values. It is a custom operation we have to write. And we will use JavaScript to write it, because it will be easier than regular Automation. When calling JavaScript Automation, a prefix must be added to the name of the operation. In our example, for the operationId
key, we set the javascript.getValuesForClaimType
value.
The last and final step: Write the getValuesForClaimType
operation. The algorithm actually is dead simple: We call the default operation, Directory.SuggestEntries
, used to fetch values when you don’t override anything. This is a very cool way of getting values because you don’t have to JSON format them the way they are expected in the widget, it’s already done.
Our chain receives the temp
object we modified in the inline JavaScript a few step above. Basically, the temp
object becomes the params
argument of our run
JavaScript function. And it also contains all the setting of the widget itself, you know, things like “Fetch Mode”, “Localize”, etc., so it is very easy to pass them back to the operation. params.searchterm
is the one not to be omitted, for sure.
Our chain is a simple wrapper to the default operation, just changing the directory.
bash function run(input, params) { var entries = Directory.SuggestEntries( null, { directoryName: params.claimType, absoluteLabelSeparator: params.absoluteLabelSeparator, canSelectParent: params.canSelectParent, caseSensitive: params.caseSensitive, contains: params.contains, dbl10n: params.dbl10n, displayObsoleteEntries: params.displayObsoleteEntries, filterParent: params.filterParent, keySeparator: params.keySeparator, labelFieldName: params.labelFieldName, lang: params.lang, localize: params.localize, searchTerm: params.searchTerm }); return entries; }
And here is the awesome, incredible result in an amazing video:
Since this blog already is long, let’s make it even longer with an example of tuning the JavaScript. This way, I may finally get the “Longest Nuxeo Blog Award”. In the previous example, we built our vocabularies so that the ID of a ClaimType
matched the ID of another vocabulary. If you wanted to share some values (for example, “Accident” and “breakdown” display the same subtype), you would just switch..case
the thing:
bash function run(input, params) { var entries, directoryToUse; switch(claimType) { case "Robbery": directoryToUse = "Robbery"; break; case "Breakdown": case "SeriousBreakdown": directoryToUse = "Breakdown"; break; // By default, we use "Accident" default: directoryToUse = "Accident"; break; }
entrie = Directory.SuggestEntries( null, { directoryName: directoryToUse, . . . etc . . . }); return entries; }
Long, but interesting. I think. I believe. I hope.