Suggest Widget

Version 60.1 by Adel Atallah on 2018/10/23
Warning: For security reasons, the document is displayed in restricted mode as it is not the current version. There may be differences and errors due to this.

Failed to execute the [velocity] macro. Cause: [The execution of the [velocity] script macro is not allowed in [xwiki:Documentation.DevGuide.FrontendResources.AutoSuggestWidget.WebHome]. Check the rights of its last author or the parameters if it's rendered from another script.]. Click on this message for details.

This is a Javascript widget bundled by default with the XWiki platform.

Usage

The suggest widget can be triggered when typing something in a text field. The suggested list can contain field values from a class defined in your wiki, data retrieved from a custom document or a REST resource, or any custom information you provide.

Suggest fields from a class defined in the wiki

Use information from a predefined class in your wiki (e.g. XWiki.TagClass, XWiki.XWikiUsers, etc.) or from a class defined by yourself.

For example, use XWiki.TagClass to suggest tags from the wiki tag cloud:

suggest.png

$!xwiki.jsx.use("DevGuide.AutoSuggestWidgetExample")
<form method="post" action="#">
 <label for="myinput">Type the name of a tag and test the suggest list:</label>
 <input id="myinput" size="20" type="text" value=""/>
</form>

The JavascriptExtension object from the AutoSuggestWidgetExample page contains the Javascript code to enable the widget when focusing on the text field:

(function(){
 document.observe('dom:loaded', function () {
   if($('myinput')) {
     Event.observe($('myinput'), "focus", function() {
       new XWiki.widgets.Suggest(this, {
            script: '$xwiki.getURL("${doc.space}.WebHome", "view")?xpage=suggest&classname=XWiki.TagClass&fieldname=tags&secCol=-&',
            varname: "input",
            seps: " ,|",
            offsety: 13
        });
      });
    }
  }); // end of doc observe
})();

Options used in the suggest.vm template:

OptionDetails
xpageFor class properties use xpage=suggest because the suggest.vm template can handle such requests.
classnameThe name of the class for the elements of the suggest list.
fieldnameThe field name from the class considered for the suggest list.
firColFirst column of the list of results.
secColSecond column of the list of results. For a user defined query, use - value for one column and no hidden input. Otherwise the list of results will have two columns and a hidden input.

Example

Check out the example for class field values at Class Field Example

Suggest custom information

When the information you want to suggest is not available through a class field or you generate it using a custom query, you need to create a service (plain wiki page called with the get action and with outputSyntax=plain parameter in the url, for example: xwiki/bin/get/Space/Page?outputSyntax=plain) that maps your results to the xml input accepted by the widget. For example, you can build a list of suggestions that contains the wiki page names within a certain space:

customsuggest.png

$!xwiki.jsx.use("DevGuide.AjaxSuggestCustomExample")
<form method="post" action="#">
 <label for="myinput">Type the name of an example page from the <tt>DevGuide</tt> space and test the suggest list:</label>
 <input id="myinput_suggest" size="20" type="text" value=""/>
 <input id="myinput" type="hidden" />
 <input id="mybutton" type="button" value="Go" /><br/>
</form>

The JavascriptExtension object from the AjaxSuggestCustomExample page contains the Javascript code to enable the widget when focusing on the text field. Also, the script option uses the URL for the results page. 

(function(){
 document.observe('dom:loaded', function () {
   if($('myinput_suggest')) {
     Event.observe($('myinput_suggest'), "focus", function() {
       new XWiki.widgets.Suggest(this, {
             script: "$xwiki.getURL('Documentation.DevGuide.FrontendResources.AutoSuggestWidget.SuggestService', 'get', 'outputSyntax=plain&spacename=Documentation.DevGuide')&",
             varname: "input",
             seps: " ,|",
             offsety: 13,
             minchars: 3
        });
      });
    }
  }); // end of doc observe
})();

The service page uses a query to get all the pages from the space provided using spacename parameter in the URL. The generated response must be an xml file that has <results> as a root node and <rs> as children.

##
## Service to generate the suggest list of files from a certain space.
## @spacename
## @input
##
#set($input = $request.get("input").toLowerCase())
#set($spacename = $request.get("spacename"))
$response.setContentType("text/xml") ## generate a xml file
## select pages
#if("$!input" == "")
  #set($query = "where doc.space='$spacename' and doc.name<>'WebHome' and doc.name<>'WebPreferences' order by doc.date desc")
#else
  #set($query = "where doc.space='$spacename' and doc.name<>'WebHome' and doc.name<>'WebPreferences' and lower(doc.name) like '%" + $input + "%' order by doc.date desc")
#end
#set($searchresults = $xwiki.searchDocuments($query, 30, 0))
<results space="$spacename">
  #foreach($result in $searchresults)
    #set($resultDoc = $xwiki.getDocument($result))
    #set($resultDocName = $resultDoc.name)
    #set($resultDocURL = $resultDoc.getURL())
   <rs id="1" info="$resultDocURL">$resultDocName</rs>
  #end  
</results>

To provide autosuggest to several elements on the form, you can use JavaScript to loop through all the form elements and provide autosuggest if they meet certain conditions. In the example below, if there are form elements with id Supplier in the form, they get assigned a suggest widget that uses the Suppliers space as its source. If the element id matches Product, the suggest is told to use the Products space as its source instead. 

This method can be very useful when a form contains a lot of similar elements that require autosuggest. If you make sure the naming is done consistently, you can also use javascript to assign autosuggest based on part of the element id, for example 'all elements ending with _foo' or 'all elements starting with Bar_'. You can use the velocity code from the example above with the code below.

(function(){
document.observe('dom:loaded', function () {
 myForm = document.getElementById('inline').elements;
 for(i=0; i<myForm.length; i++){
  if(myForm[i].id =='Supplier'){
   mySuggest(myForm[i], 'Suppliers');
   }
  if(myForm[i].id=='Product'){
   mySuggest(myForm[i], 'Products');
   }
  }
 }); // end of doc observe
})();

function mySuggest(element, space) {
if (!element.suggest) {
 element.suggest =  new XWiki.widgets.Suggest(element, {
 script: "$xwiki.getURL('Sandbox.AutoSuggest', 'get', 'outputSyntax=plain&spacename=')"+space+"&",
 varname: "input",
 seps: " ,|",
 offsety: 13,
 minchars: 1
  });
 }
}

Example

Check out the example for custom information at Custom Information Example

Suggest Users or Groups from the wiki

Local or global users and groups from the wiki can be suggested using the uorgsuggest.vm template.

Example:

$xwiki.jsx.use("$doc.fullName")##

<input name="userInput" id="userInput" value="" type="text"/> 

Here is the code that made the suggestion of global users from the wiki possible:

...
<input name="userInput" id="userInput" value="" type="text"/>
...
(function(){
 document.observe('dom:loaded', function () {
   if($('userInput')) {
     Event.observe($('userInput'), "focus", function() {
       new XWiki.widgets.Suggest(this, {
             script: '$xwiki.getURL("${doc.fullName}", "view")?xpage=uorgsuggest&classname=XWiki.XWikiUsers&wiki=global&uorg=user&',
            varname: "input",
            seps: " ,|",
            delay : 200,
            timeout: 5000,
            offsety: 13
        });
      });
    }
  }); // end of doc observe
})();

Search suggest shows document title but searches by document name

Example:

The request


#set($suggestURL = $xwiki.getURL('Main.WebHome', 'view', "&xpage=suggest&classname=SomeSpace.SomeClass&fieldname=entity&firCol=obj.name&secCol=doc.title"))

onfocus='new XWiki.widgets.Suggest(this, {script:"$escapetool.javascript("${suggestURL}&")", varname:"input",  callback: function(obj) {resource.onChangeEntity(obj.info, obj.value);}} )'

The JavascriptExtension object


// entityValue is the document name and entityInfo is the document title
    onChangeEntity: function(entityValue, entityInfo) {
     // Update entity value
     $('SomeSpace.SomeClass_0_entity_suggest').value = entityInfo;
      var serviceURL = new XWiki.Document('SomePageOne', 'SomeSpace').getURL('view');
      var ajx = new Ajax.Request(serviceURL, {
       method: 'get',
       parameters: 'xpage=plain&outputSyntax=plain&entity=' + encodeURIComponent(entityValue)
     }
   }

Javascript parameters for the XWiki.widgets.Suggest constructor

ParameterDetailsDefault value
classNameThe CSS classname of the suggest list.ajaxsuggest
mincharsThe minimum number of characters after which to trigger the suggest.1
delayThrottle delay: how much to wait after a keypress before requesting suggestions from the server, in milliseconds.500
timeoutHow long to display the list of suggestions, in milliseconds. If the user doesn't interact with the suggestions before the timeout expires, the list will be cleared.2500 (2.5 seconds).
offsetyHow much to shift the list of suggestions vertically from the normal position, in pixels. This allows, for example, room for extra decorations between the input and the list.0
shownoresultsWhat to do when no results match the current input: display a "no results" message (true), or simply hide the suggest box when no suggestions are available (false).true
noresultsDefault displayed message when shownoresults is enabled and there are no results to display.No results! (translation key core.widgets.suggest.noResults)
hideButtonControls whether a hide suggestions button (or two) is displayed or not. If used, must be a map (JS Object) with two possible keys: hideButton.positions is an array that accepts as values top and bottom, specifying where to place hide buttons, and hideButton.text is the text that should be displayed.{positions: ['top'], text: 'hide suggestions'} (translation key core.widgets.suggest.hide)
cacheCache the list suggestions returned for a specific input for the lifetime of the current page.false
sepsIf suggestions should be returned for each token instead of the full text in the input, set this to a list of characters that should be used for splitting the input into tokens. Leave empty to skip tokenizing and use the whole text instead.Empty string
parentContainerThe id of the element that will hold the suggest element. Useful when the enhanced input is not statically positioned, for example in a modal dialogbody
sourcesArray of sources from where to fetch suggestions. If there are any entries in this array, then the suggest functions in multi-source mode; if not, then the suggest is in single-source mode. Every entry should be a map (JS Object), and the following parameters should be used as keys in every such map instead of keys in the global options.None, by default the suggest is in single-source mode
scriptURL for the ajax request that will get the suggested list. Must end with & because varname parameter will be appended. Use suggest.vm to get field values from a wiki class or a custom URL to generate the suggested list.None, this parameter is mandatory
varnameThe name of the request parameter holding the input stub.input
methodThe HTTP method for the AJAX request.get
resultsParameterThe name of the JSON variable or XML element holding the results.results for XML results, must be changed to searchResults for the REST search
resultIdThe name of the JSON parameter or XML attribute holding the result identifier.id for both the old suggest and the REST search
resultValueThe name of the JSON parameter or XML attribute holding the result value.value for the old suggest, must be changed to pageFullName for the REST search
resultInfoThe name of the JSON parameter or XML attribute holding the result auxiliary information.info for the old suggest, must be changed to pageFullName for the REST search
iconAn icon to display for every entry in the results fetched from this source.None, no icon is displayed
highlightShould results fragments be highlighted when matching typed input.true
alignControl where the suggest box will be displayed. Possible values are: left, center, right.
Since 6.2: there is also the auto value, that will place the search box from the left of the input box unless there is not enough place to display it entirely, otherwise it will be displayed from the right.
right
propagateEventKeyCodesA sublist of key codes, from the list of keys handled by this widget, for which to propagate the keyboard event. Useful when another keyboard event listener exists on the input field, even if it may be registered at a difference level. See the onKeyPress in the code for a clearer picture.Empty list. By default, none of the handled key events propagate. All other, not handled, events do.

Velocity macros

You can use velocity macros to insert the suggest widgets.

Page picker widget

page-picker.jpg

The page picker widget can be inserted on a page using the following code:
{{velocity}}
{{html}}
  #pagePicker()
{{/html}}
{{/velocity}}

You can specify the HTML attributes of the select by doing this:
#set ($parameters = {'multiple': 'multiple', 'id': 'my-id'})
#pagePicker($parameters)

Tips

Bugs we know about

The suggest feature will not work if the page called by the widget is not saved with programming rights (see details on this issue).

   

Get Connected