> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# Materials: FACT-Finder suggest layer

> The templates for the FACT-Finder suggest layer in both variants: JavaScript and CSS for the simple suggestion list and for the extended layer with product images.

The suggest layer shows search suggestions while the visitor types. It queries FACT-Finder directly, independently of the search results page. This page contains the templates for it in both variants.

> [!WARNING]
>
> **The direct integration is deprecated and no longer supported.** It is only available up to FACT-Finder 6.9 and is neither maintained nor developed further by WEBSALE. For new integrations, use the FACT-Finder WebComponents according to the official FACT-Finder documentation.
>
> This page is intended for existing shops that still work with the direct integration.

Guide: FACT-Finder integration · Materials: FACT-Finder templates

## Two variants

| | simple layer | extended layer |
| - | - | - |
| Files | `ff_suggest.js`, `ff_suggest.css` | `ff_big_suggest.js`, `ff_big_suggest.css` |
| Display | a table with suggestion, type, and hit count | two columns, product suggestions with images next to search terms |
| Prerequisite | none, plain JavaScript | jQuery |
| Response format | text, line by line, fields separated by `###` | JSONP |
| Keyboard | up and down | up, down, left, right, and Tab |
| Callback functions | two | four |

Both use the same CSS class names for the rows, but the stylesheets are not interchangeable. The simple layer builds a table, the extended one builds lists in two columns.

## The simple suggest layer

### ff\_suggest.js

The file defines a constructor `FFSuggest`. You create an instance and call `init()` with eight parameters.

| Parameter | Meaning |
| - | - |
| `searchURL` | the address of the FACT-Finder suggest interface |
| `formname` | the name of the search form in the document |
| `queryParamName` | the name of the search input field |
| `divLayername` | the ID of the `div` the layer is written into |
| `instanceName` | the name of your instance, as a string. The module uses it to build the `onMouseOver` calls in the generated HTML |
| `debugMode` | `true` displays errors as alert boxes |
| `channelParamName` | the name of the channel parameter |
| `channel` | the channel itself |

> [!WARNING]
>
> `instanceName` must exactly match the name of the variable under which you created the instance. The module inserts this name as text into the generated `onMouseOver` and `onMouseDown` attributes. If it doesn't match, the layer stays silent without any error message.

> [accordion] ff\_suggest.js
>
> ```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> function FFSuggest() {
>
> 	var pRequest;
> 	var pLayer;
> 	var pDebug			= false;
> 	var pInstanceName		= '';
> 	var pSearchURL			= '';
> 	var pQueryParamName		= '';
> 	var pFormname 			= '';
> 	var pLayerName			= '';
> 	var pQueryInput;
> 	var pSuggest			= new Array();
> 	var pLastQuery;
> 	var pCurrentSelection		= -1;
> 	var submitted			= false;
>
> 	var pSuggestQueryClass 		= 'suggestTextQuery';
> 	var pSuggestTypeClass 		= 'suggestTextType';
> 	var pSuggestAmountClass         = 'suggestTextAmount';
> 	var pSuggestQueryTypedClass     = 'suggestTextQueryTyped';
> 	var pSuggestFooterClass         = 'suggestFooter';
> 	var pSuggestHeaderClass         = 'suggestHeader';
> 	var pSuggestRowClass	        = 'suggestRow';
> 	var pSuggestHighlightClass      = 'suggestHighlight';
>
> 	this.init = function(searchURL, formname, queryParamName, divLayername, instanceName, debugMode, channelParamName, channel) {
> 		pSearchURL		= searchURL;
> 		pFormname		= formname;
> 		pQueryParamName		= queryParamName;
> 		pChannelParamName	= channelParamName;
> 		pChannel		= channel;
> 		pLayerName		= divLayername;
> 		pInstanceName		= instanceName;
> 		pDebug			= debugMode;
> 		if (pSearchURL == '') {
> 			if (pDebug) alert('no searchurl defined');
> 			return null;
> 		} else if (pInstanceName == '') {
> 			if (pDebug) alert('no instancename defined');
> 			return null;
> 		} else if (pFormname == '') {
> 			if (pDebug) alert('no formname defined');
> 			return null;
> 		} else if (pQueryParamName == '') {
> 			if (pDebug) alert('no queryparamname defined');
> 			return null;
> 		} else if (pLayerName == '') {
> 			if (pDebug) alert('need a layer for output');
> 		}
> 		pQueryInput = document[pFormname][pQueryParamName];
> 		pQueryInput.onkeyup	= handleKeyPress;
> 		pQueryInput.onfocus	= showLayer;
> 		pQueryInput.onblur	= hideLayer;
> 		document[pFormname].onsubmit = handleSubmit;
> 	}
>
> 	function handleSubmit() {
> 		submitted = true;
> 		if (pSuggest[pCurrentSelection] != undefined) {
> 			document[pFormname][pQueryParamName].value = pSuggest[pCurrentSelection].split('###')[0];
> 			if(document[pFormname]['queryFromSuggest'] != null){
> 				document[pFormname]['queryFromSuggest'].value = true;
> 			}
> 		}
> 	}
>
> 	this.handleClick = function() {
> 		if (pSuggest[pCurrentSelection] != undefined) {
> 			document[pFormname][pQueryParamName].value = pSuggest[pCurrentSelection].split('###')[0];
> 			if(document[pFormname]['queryFromSuggest'] != null){
> 				document[pFormname]['queryFromSuggest'].value = true;
> 			}
> 			document[pFormname].submit();
> 		}
> 	}
>
> 	this.handleMouseOver = function(pos) {
> 		var tblCell = getTableCell(pos);
> 		unmarkAll();
> 		if (tblCell != null) {
> 			highlightSuggest(tblCell);
> 			pCurrentSelection = pos;
> 		}
> 	}
>
> 	this.handleMouseOut = function(pos) {
> 		var tblCell = getTableCell(pos);
> 		if (tblCell != null) {
> 			unmarkSuggest(tblCell);
> 			pCurrentSelection = -1;
> 		}
> 	}
>
> 	function handleKeyPress(evt) {
> 		evt = (evt) ? evt : ((event) ? event : null);
> 		var keyCode = evt.keyCode;
> 		if (keyCode == 38) {
> 			moveSelection('up')
> 		} else if (keyCode == 27) {
> 			hideLayer();
> 		} else if (keyCode == 40) {
> 			moveSelection('down');
> 		} else {
> 			if (pQueryInput.value == '') {
> 				hideLayer();
> 				if (pLayer != null){ pLayer.innerHTML = ''; }
> 				return null;
> 			}
> 			if (pLastQuery != pQueryInput.value){ startAjax(); }
> 			pLastQuery = pQueryInput.value;
> 		}
> 	}
>
> 	function moveSelection(direction) {
> 		var pos = pCurrentSelection;
> 		if (direction == 'up'){	pos--; }
> 		else{					pos += 1; }
>
> 		if (pos < 0) {
> 			unmarkAll();
> 			pQueryInput.focus();
> 			pCurrentSelection	= -1;
> 		} else {
> 			var tblCell = getTableCell(pos);
> 			if (tblCell != null) {
> 				unmarkAll();
> 				highlightSuggest(tblCell);
> 				pCurrentSelection = pos;
> 			}
> 		}
>
> 		var query = pQueryInput.value;
> 		pQueryInput.value = '';
> 		pQueryInput.focus();
> 		pQueryInput.value = query;
> 	}
>
> 	function startAjax() {
> 		var query = pQueryInput.value;
> 		if(query.length > 50 ){ return; }
>
> 		var requestURL = pSearchURL +'?query='+ encodeURIComponent(query) +'&'+ pChannelParamName +'='+ pChannel;
>
> 		try {
> 			if( window.XMLHttpRequest ) {
> 				pRequest = new XMLHttpRequest();
> 			} else if( window.ActiveXObject ) {
> 				pRequest = new ActiveXObject( "Microsoft.XMLHTTP" );
> 			} else {
> 				if (pDebug) alert( 'no ajax connection' );
> 			}
>
> 			pLayer = document.getElementById(pLayerName);
> 			if (pLayer != null) {
> 				if (query != '') {
>
> 					pRequest.open( "GET", requestURL, true );
> 					pRequest.onreadystatechange = callbackAjax;
> 					pRequest.send( null );
> 				} else {
> 					hideLayer();
> 				}
> 			} else {
> 				if (pDebug) alert( 'no layer for output found' );
> 			}
> 		} catch( ex ) {
> 			hideLayer();
> 			if (ex != undefined) {
> 				if (pDebug) alert( 'Error: ' + ex );
> 			} else {
> 				if (pDebug) alert( 'Error: unbekannter Fehler' );
> 			}
> 		}
> 	}
>
> 	function hideLayer() {
> 		if (pLayer != null) {
> 			pLayer.style.display = 'none';
> 			fireSuggestLayerHidden();
> 		}
> 	}
>
> 	this.hideLayerOutsideCall = function() {
> 		if (pLayer != null) {
> 			pLayer.style.display = 'none';
> 			fireSuggestLayerHidden();
> 		}
> 	}
>
> 	function showLayer() {
> 		if (pLayer != null && pSuggest != null && pSuggest.length >= 1) {
> 			pLayer.style.display = 'block';
> 		}
> 	}
>
> 	function callbackAjax() {
> 		if (submitted == false) {
> 			if (pRequest.readyState == 4) {
> 				if (pRequest.status != 200) {
> 					hideLayer();
> 					if (pDebug) alert( 'Error (' + pRequest.status + '): ' + pRequest.statusText );
> 				} else {
> 					handleResponse(pRequest.responseText);
> 				}
> 			}
> 		}
> 	}
>
> 	// calls the callback for "outside" listeners if the callback is implemented
> 	function fireSuggestCompleted(suggestLayerIsVisible) {
> 		if (typeof(onSuggestCompleted) == 'function') {
> 			onSuggestCompleted(suggestLayerIsVisible);
> 		}
> 	}
>
> 	// calls the callback for "outside" listeners if the callback is implemented
> 	function fireSuggestLayerHidden() {
> 		if (typeof(onSuggestLayerHidden) == 'function') {
> 			onSuggestLayerHidden();
> 		}
> 	}
>
> 	function handleResponse(text) {
> 		pCurrentSelection = -1;
> 		pSuggest = new Array();
> 		pSuggest = text.split('\n');
> 		var outputText = '<table cellpadding="0" cellspacing="0" class="' + pLayerName + '" width="100%" border="0" onMouseDown="' + pInstanceName + '.handleClick();">';
> 		outputText += '<tr class="'+pSuggestHeaderClass+'" ><td nowrap="nowrap" colspan="3">Vorschläge zu Ihrer Suche...</td></tr>';
>
> 		var pNewSuggest = new Array();
> 		for (var i = 0; i < pSuggest.length; i++) {
> 			var firstChar = pSuggest[i].charCodeAt(0);
>
> 			if (firstChar != 13 && firstChar != 10 && pSuggest[i].length >= 1) {
> 				pNewSuggest.push(pSuggest[i]);
> 			}
> 		}
> 		pSuggest = pNewSuggest;
> 		var query = pQueryInput.value;
>
> 		for (var i = 0; i < pSuggest.length; i++) {
> 			pSuggestParts = new Array();
> 			pSuggestParts = pSuggest[i].split("###");
>
> 			outputText += '<tr id="' + pLayerName + '_' + i + '" class="'+pSuggestRowClass+'" onMouseOver="' + pInstanceName + '.handleMouseOver(' + i + ');" onMouseOut="' + pInstanceName + '.handleMouseOut(' + i + ');">'
> 								+'<td nowrap="nowrap" class="'+ pSuggestQueryClass +'">' + pSuggestParts[0].replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>') + '</td>'
> 								+'<td nowrap="nowrap" class="'+ pSuggestTypeClass +'">' + pSuggestParts[2] + '</td>'
> 								+'<td nowrap="nowrap" class="'+ pSuggestAmountClass +'">' + pSuggestParts[1] + '</td>'
> 						+'</tr>';
> 		}
> 		outputText += '<tr><td class="'+pSuggestFooterClass+'" colspan="3"> </td></tr></table>';
> 		if (pSuggest.length >= 1) {
> 			showLayer();
> 			pLayer.innerHTML = outputText;
>
> 			// callback for "outside" listeners
> 			fireSuggestCompleted(true);
> 		} else {
> 			hideLayer();
> 			pLayer.innerHTML = '';
>
> 			// callback for "outside" listeners
> 			fireSuggestCompleted(false);
> 		}
>
> 	}
>
> 	function highlightSuggest(tblCell) {
> 		tblCell.className = pSuggestHighlightClass;
> 	}
>
> 	function unmarkSuggest(tblCell) {
> 		tblCell.className = pSuggestRowClass;
> 	}
>
> 	function unmarkAll() {
> 		var tblCell;
> 		for (var i = 0; i < pSuggest.length; i++) {
> 			tblCell = getTableCell(i);
> 			if (tblCell != null) {
> 				unmarkSuggest(tblCell);
> 			}
> 		}
> 	}
>
> 	function getTableCell(pos) {
> 		var tblCell;
> 		tblCell = document.getElementById(pLayerName + '_' + pos);
> 		return tblCell;
> 	}
> }
> ```

> [!NOTE]
>
> The module doesn't query FACT-Finder on every keystroke. It first compares with the last request and skips search terms longer than 50 characters entirely.
>
> The response is plain text: one line per suggestion, containing three fields separated by `###` in the order suggestion, hit count, type. In the generated HTML they appear in the order suggestion, type, hit count.

> [!WARNING]
>
> The heading "Vorschläge zu Ihrer Suche..." is hard-coded in the JavaScript. If your shop is multilingual, extract this text and pass it in from outside.

### ff\_suggest.css

> [accordion] ff\_suggest.css
>
> ```css theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> /*****************************************************************************/
> /*** FACT-FINDER SUGGEST ***/
> /*****************************************************************************/
>
> /* needed otherwise the searchBoxLine will pop-up in IE */
> div.suggestFormWrap{
>    position:absolute;
>    z-index: 999;
> }
> div.suggestLayer{
>    position: absolute;
>    z-index: 999;
>    top: 125px;
>    left: 291px;
>    width: 1px;
>    height: 1px;
>    display: none;
>    padding: 0;
>    margin: 0;
>    font-family: Arial,Helvetica,sans-serif;
> }
> table.suggestLayer{
>    z-index:999;
>    position:absolute;
>    font-size: 11px;
>    width: 297px;
>    border-right: 1px solid #85B916;
>    border-bottom: 1px solid #85B916;
>    border-left: 1px solid #85B916;
>    height: 12px;
>    background-color: white;
>    color: black;
>    cursor: pointer;
>    text-align: left;
> }
> tr.suggestLayer{
>    height: 12px;
> }
> td.suggestLayer{
>    padding: 0;
>    height: 12px;
> }
> tr.suggestHeader{
>    font-weight: normal;
>    font-size: 11px;
> }
> tr.suggestHeader td{
>    background-color: #eeeeee;
>    border-bottom:1px solid #fff;
>    padding: 5px 10px;
>    color: #393939;
>    font-weight: normal;
> }
> td.suggestFooter{
>    height:1px;
> }
> td.suggestTextQuery{
>    font-weight: bold;
>    padding: 2px 15px 2px 10px;
> }
> span.suggestTextQueryTyped{
>    color: #85B916;
>    text-decoration: underline;
> }
> td.suggestTextType{
>    padding: 2px 5px 2px 15px;
>    width: 30%;
>    background-color: #85B916;
> }
> td.suggestTextAmount{
>    padding: 2px 5px 2px 15px;
>    width: 30%;
>    text-align: right;
>    background-color: #85B916;
> }
> tr.suggestRow{
>    padding: 2px 2px 2px 0px;
>    background-color: #FCFCFC;
> }
> tr.suggestHighlight{
>    color: black;
>    background-color: #85B916;
> }
> tr.suggestHighlight span.suggestTextQueryTyped{
>    color: #fff;
> }
> ```

> [!NOTE]
>
> The values for `top` and `left` on `div.suggestLayer` are tailored to a specific shop design. Adjust them to your header, or position the layer relative to the search field.

## The extended suggest layer

The extended layer splits the suggestions into two columns: product suggestions with images on the left, the remaining search terms on the right. It requires jQuery, fetches the suggestions via JSONP, and responds to more keys.

### Which version you need

The previous documentation provides four files, one for each combination of jQuery version and FACT-Finder version. Together they differ in thirteen lines. This page therefore shows one version and describes the two deviations.

| Your environment | What to do |
| - | - |
| jQuery 3, FACT-Finder 6.8 or 6.9 | use the template unchanged |
| jQuery 2, FACT-Finder 6.8 or 6.9 | change one line, see below |
| FACT-Finder 6.10 | add one line, see below |

Check with Omikron which FACT-Finder version you use.

### The deviation for jQuery 2

jQuery 3 removed `.error()`. The template therefore uses `.fail()`. For jQuery 2, change this one line at the end of `getSuggestions()` back:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
.error(function (e, xhr, settings, exception) {
```

### The deviation for FACT-Finder 6.10

As of 6.10, FACT-Finder no longer returns the suggestions as a bare array but wraps them in an object with the property `suggestions`. The previous documentation solves this with a separate file in which every use of `jsonObj` is replaced by `pSuggest`.

There's a simpler way. In the response function of `getSuggestions()`, add one line directly after `pCurrentSelection = -1;`:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
$.getJSON(requestURL,
	function (jsonObj, textStatus) {
			pCurrentSelection = -1;
			if (jsonObj && jsonObj.suggestions) { jsonObj = jsonObj.suggestions; }
			if (jsonObj != null && jsonObj.length > 0) {
```

After that, `jsonObj` is the array of suggestions in both FACT-Finder versions, and the rest of the file remains unchanged.

> [!WARNING]
>
> This consolidation was added here and hasn't been tested in any shop. It follows from comparing the two original files, whose only substantive difference is this unwrapping. Test it in a test shop before you adopt it.
>
> At one point, the original file for 6.10 contains `pSuggest[i] = pSuggest[i];`, an assignment with no effect. It came about during renaming from `pSuggest[i] = jsonObj[i];` and is further evidence that the four files were derived from each other mechanically.

### The parameters of init()

Here `init()` takes fourteen parameters instead of eight. The first eight are the same as for the simple layer.

| Parameter | Meaning |
| - | - |
| `showImages` | `true` shows product images in the left column |
| `sid` | the visitor's session ID, passed on to FACT-Finder |
| `uid` | the customer ID |
| `site` | an identifier of the environment, for example the shop name |
| `displayElementCallback` | a function that is called for each displayed suggestion |
| `translation` | an object with the labels, see below |

> [!NOTE]
>
> `sid`, `uid`, and `site` are only appended if they are filled. They end up both in the suggest request and in the target link that a clicked suggestion opens. FACT-Finder evaluates them for its statistics.

### The translation object

Unlike the simple layer, the extended one contains no hard-coded texts. It expects them in the `translation` parameter:

| Key | Usage |
| - | - |
| `product` | the singular after a hit count of one |
| `products` | the plural. The placeholder `{0}` is replaced by the number |
| `<typ>.headline` | the heading per suggestion type, for example `productName.headline` |

If a heading is missing, the module uses the technical type name. This was added here; the previous documentation doesn't describe the parameter.

### The callback functions

Three of them are global functions that you simply define. You pass the fourth to `init()`.

| Function | Is called |
| - | - |
| `onSuggestCompleted(sichtbar)` | after the suggestions have been rendered. The parameter indicates whether the layer is visible |
| `onSuggestLayerHidden()` | after the layer has been hidden |
| `onSubmitSuggest(vorschlag)` | when the visitor selects a suggestion. If the function returns an address, the browser goes there instead of to the link suggested by FACT-Finder |
| `displayElementCallback(begriff, typ, refKey)` | for each individual displayed suggestion |

> [!NOTE]
>
> `displayElementCallback` runs with a delay; the module defers each call by ten milliseconds. So don't rely on the layer still being visible inside it.
>
> With `onSubmitSuggest`, you attach your own target pages to suggestions, for example to send a category suggestion directly to the category page instead of to the search.

### The classes the module expects

The module inserts these classes into the generated HTML itself. Your stylesheet must define them.

| Class | Element |
| - | - |
| `suggestLayerBlockText` | the right column with the search terms |
| `suggestLayerBlockImage` | the left column with the product suggestions |
| `suggestHeader` | a heading per suggestion type |
| `suggestRow` | a suggestion row |
| `suggestRowWithImage` | a suggestion row with product image |
| `suggestHighlight` | the currently selected row |
| `suggestImage` | the product image |
| `suggestTextQuery` | the suggestion text |
| `suggestTextQueryTyped` | the part of the suggestion the visitor has already typed |
| `suggestTextAmount` | the hit count |
| `suggestParentCategory` | the parent category of a product suggestion |
| `noborder` | added to the image column when the text column stays empty |

### ff\_big\_suggest.css

> [accordion] ff\_big\_suggest.css
>
> ```css theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> /*****************************************************************************/
> /*** SUGGEST Fact Finder ***/
> /*****************************************************************************/
>
> /* Abweichungen normale Styles */
> #head {
>    position: relative;
> }
>
> #head_search {
>    position: static !important;
> }
>
> /* SUGGEST */
> div.suggestLayer{
>    display: none;
>    top: 85px;
>    right:0px;
>    padding: 0;
>    position: absolute;
>    z-index: 1000;
>    font-size: 1em;
>    font-weight:bold;
>    color: #595959;
>    border: 1px solid #486891;
>    }
>
> ul.suggestLayerList,
> ul.suggestLayerBlock,
> div.suggestLayerBlock{
>    width: 988px;
>    left:0px;
>    top: 39px;
>    cursor: pointer;
>    float: left;
>    font-size: 1em;
>    list-style: none outside none;
>    background: #ebeff3;
>    border: 1px solid #f9f8f8;
>    }
>
> .suggestLayerBlockText{
>    float: right;
>    width: 242px;
>    padding: 0px 20px 16px 20px;
>    background:#486891;
>    color:#fff;
>    height:100%;
>    }
>
> .suggestLayerBlockImage{
>    float: left;
>    width: 670px;
>    padding: 0px 0px 16px 20px;
>    }
>
> ul.suggestLayerList li,
> ul.suggestLayerBlock li,
> ul.suggestLayerBlockText li,
> ul.suggestLayerBlockImage li{
>    display: block;
>    list-style: none outside none;
>    }
>
> ul.suggestLayerBlockText li:hover span.suggestTextQuery{
>    color: #fff;
>    text-decoration:underline;
>    }
>
> ul.suggestLayerBlockImage li:hover span.suggestTextQuery{
>    color: #004287;
>    text-decoration:underline;
>    }
>
> .suggestLayerBlockText span.suggestTextQueryTyped{
>    color:#fff;
>    text-decoration:underline;
>    }
>
> .suggestLayerBlockImage span.suggestTextQueryTyped{
>    color:#004287;
>    text-decoration:underline;
>    }
>
> li.suggestHeader,
> li.suggestHeader:hover{
>    font-size: 14px;
>    text-transform:uppercase;
>    clear:both;
>    float:none;
>    color:#004287;
>    font-weight:normal;
>    text-align:left;
>    padding:20px 0px 8px 0px;
>    }
>
> .suggestLayerBlockText li.suggestHeader,
> .suggestLayerBlockText li.suggestHeader:hover{
>    color:#fff;
>    }
>
> .suggestLayerBlockText > li.suggestHeader:first-child,
> .suggestLayerBlockImage > li.suggestHeader:first-child{
>    margin-top:0px;
>    }
>
> .suggestLayerBlockImage > li.suggestHeader:first-child{
>    line-height:15px;
>    }
>
> .suggestLayerBlockImage li span.suggestTextQuery,
> .suggestLayerBlockText li span.suggestTextQuery{
>    display: block;
>    overflow: hidden;
>    font-weight:normal;
>    text-align: left;
>    font-size: 1em;
>    }
>
> .suggestLayerBlockText li.suggestRow{
>    line-height: 20px;
>    padding-left: 10px;
>    background: url(../../images/web/navi_level_2.gif) no-repeat 0px 10px;
> }
>
> span.suggestTextAmount{
>    display: block;
>    float:right;
>    margin-top: -19px;
>    font-weight: normal;
>    color: #fff;
>    width: 50px;
>    font-size: 11px;
>    }
>
> .suggestLayerBlockImage li.suggestRow{
>    padding-right: 16px;
>    margin-top: 8px;
>    float:left;
>    }
>
> li.suggestRowWithImage{
>    height: 75px;
>    width: 300px;
>    background:#ffffff;
>    margin: 0px 10px 0px 0px;
>    }
>
> span.suggestImage{
>    float: left;
>    height: 75px;
>    text-align: center;
>    width: 75px;
>    background-color: #fff;
>    }
>
> ul.suggestLayerBlockImage li span.suggestTextQuery{
>    height: 70px;
>    }
>
> .suggestLayerBlockImage li span.suggestTextQuery,
> .suggestLayerBlockText li span.suggestTextQuery{
>    display: block;
>    overflow: hidden;
>    width: 190px;
>    }
>
> .suggestLayerBlockImage li span.suggestTextQuery{
>    width: 210px;
>    padding: 15px 0px 0px 15px;
>    }
>
> span.suggestImage img{
>    max-height: 75px;
>    max-width: 75px;
>    }
>
> .suggestParentCategory{
>    display:none;
>    }
>
> .search_noresult{
>    margin:40px 0;
>    }
> .search_noresult p{
>    font-size:14px;
>    font-weight:bold;
>    }
> .search_noresult ul{
>    margin:20px 0;
>    }
> ```

> [!WARNING]
>
> This stylesheet comes from a specific shop design. The fixed widths of 988, 670, and 242 pixels, the selector `#head_search`, and the background image `navi_level_2.gif` only fit there. Use it as a scaffold, not as a finished design.
>
> `.suggestParentCategory` is set to `display: none`. So the module does deliver the parent category of a product suggestion; the example merely hides it. Remove the rule if you want to show it.

### Where to get ff\_big\_suggest.js

The file itself isn't printed here. It's 509 lines long and consists almost entirely of flow logic that you adopt unchanged: keyboard control, building and tearing down the layer, assembling the links. Everything you configure in it is described above on this page.

| | |
| - | - |
| File name in the shop | `ff_big_suggest.js` |
| Version | jQuery 3 with FACT-Finder 6.8 and 6.9 |
| Source | WEBSALE, together with the rest of the FACT-Finder direct integration |

For the two deviations for jQuery 2 and FACT-Finder 6.10, change one line each, as described above.

> [!NOTE]
>
> If you don't have the file at hand, ask WEBSALE. Since the direct integration is no longer being developed, it won't change anymore.

## What both variants have in common

Both expect a search form with a name and an empty `div` for the layer. Both attach to the input field, not to a button. And both offer a function you can use to close the layer from outside:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
meineInstanz.hideLayerOutsideCall();
```

You need this if your shop should close the layer when the visitor clicks elsewhere, for example when opening the shopping cart preview.

> [!NOTE]
>
> Compared to the previous documentation, five spots in the listings have been corrected: an inverted error check that would have accessed a property of `undefined` in case of an error, the selection being preset to `0` instead of `-1`, the deprecated `escape()`, a missing semicolon, and "calback" instead of "callback" in two places.


## Related topics

- [Materials: FACT-Finder templates](https://dokumentation.websale.de/en/v8s/materialien/materialien-fact-finder-templates.md)
- [Integration of FACT-Finder](https://dokumentation.websale.de/en/v8s/integration-von-fact-finder/integration-von-fact-finder.md)
- [FACT-Finder: Filters, sorting and navigation](https://dokumentation.websale.de/en/v8s/integration-von-fact-finder/fact-finder-filter-sortierung-und-navigation.md)
- [Troubleshooting notes](https://dokumentation.websale.de/en/v8s/fehlerbehebung.md)
- [E-Search_ (basics and result list)](https://dokumentation.websale.de/en/v8s/referenz/tags/e-search/grundlagen-und-ergebnisliste.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.