# XlReactWidgetAutocomplete

Component helps with autocomplete values and in the same way does not force to use only values from the list.
If you want to oblige the user to select a value only from the certain range you might to consider using XlReactDipEnum
instead.  

### Summary

* [Exports](#exports)
* [Playground](#playground)
* [Properties](#properties)
    * [Addons](#addons)
    * [Validators](#validators)
    * [Sub Actions](#sub-actions)
    * [Suggestion Behavior](#suggestion-behavior)
* [Examples](#examples)

### Exports
```
- XlReactWidgetAutocomplete
- XlReactWidgetAutocompleteComponent
```

### Playground
* [Autocomplete Widget](https://xebialabs.github.io/xl-react-components/kitchen-sink.html#/widget/widgetAutocomplete1)
* [Autocomplete Widget (Default value)](https://xebialabs.github.io/xl-react-components/kitchen-sink.html#/widget/widgetAutocomplete2)
* [Autocomplete Widget Model Objects (Default value)](https://xebialabs.github.io/xl-react-components/kitchen-sink.html#/widget/widgetAutocomplete3)
* [Autocomplete Widget with addons](https://xebialabs.github.io/xl-react-components/kitchen-sink.html#/widget/widgetAutocomplete4)

### Properties
 - **addons** (node or array of nodes) - is added before and in line of the input component  
 - **className** (string) - control class name
 - **clearInputOnBlur** (boolean) - clears input on blur if is set as `true`
 - **disabled** (boolean) - does not allow user neither to type nor select other value if is set as `true`
 - **displayMode** (string) - 3 options are available to choose: 
      _"creation"_ or _"edit"_ - allows to make changes
      _"display"_ - makes component readonly and user can only view the current value
 - **handlers** (object) - this is required field at least need to be implemented addCandidates function that adds options in the dropdown menu
 - **inputProps** (object) - some specific props that are added as props into input
 - **invalid** (bool) - if sets as `true` makes component invalid irrelevantly of validators outcome 
 - **menuHeight** (integer) - That's a height of suggestion menu. Default height is `120 (px)`.   
 - **message** (object) - overrides default warning/error message provided in validator with provided text here. 
 - **metadata** (object) - set of parameters of the element, namely:
    - **description** - text under the input field, in case of error/warning, will be replaced with error/warning message
    - **label** - text displayed on the left side from the element. 
    - **required** - forces user to fill in the field. Shows asterisk on the label side. In case of empty value makes element invalid.
    - **requiredDirection** - Possible values 'left' or 'right'. With that variable you can control where to display asterisk, on the left or right side of label.  
    - **placeholder** - Hint shown to the user when input field is empty.
 - **model** - (object) control the current value
 - **name** - (string) - gives HTML name to an element. It's important when component is a part of the form.
 - **objLabel** - (string) - if your model is not string but object you need to specify which field consider as id 
 - **onMessageChange** - (func) - triggers once message is changed. 
 - **onModelChange** - (func) - triggers once model is changed. 
 - **onPristinityChange** - (func) - triggers once pristinity is changed. 
 - **onSuggestionNotFound** - (func) - triggers once no suggestions were found for typed value. 
 - **onSuggestionSelected** - (func) - triggers once another suggestion is selected. 
 - **onValidityChange** - (func) - triggers once validity is changed. 
 - **optionHeight** (integer) - default height is 30 (px)
 - **register** (func) - triggers when component is mounted. It contains a parameter *api*, which is an object containing 
 helpful component functions which you can invoke to do certain actions, namely
    _blur_ - to make component not focused anymore
    _erase_ - cleaning current value
    _focus_ - makes component focused
    _getSuggestions_ - returns back the list of all provided suggestions
    _resetPristinity_ - changes state of pristinity back to true
    _revealSuggestions_ - opens the list of suggestions 
 - **renderInput** (func) - custom input renderer.
 - **renderSuggestion** (func) - custom item/suggestion renderer
 - **required** (boolean) - if is set field form could not be submitted
 - **showParentMessages** (boolean) - if sets as `true` ignores own messages, but takes it from parent component. It is useful once you start
 composing components and autocomplete component only a part of it. 
 - **showSearchIcon** (boolean) - should render input field search icon, default is `true`
 - **subActions** (array of objects)- actions that can affect selecting. If is defined all those fields are required {action, isRequired, label} 
 - **suggestionBehavior** (object) - custom suggestion behavior. If is implemented it has to have those handlers (handleOnFocus,handleOnSuggestionClick, renderSuggestion)
 - **validators** (func) - that's a function which returns back an array of triggers. Read more about structure of triggers below. Validators are 
 called on every change of model. The result of the validators is to show if the component valid or not and providing a 
 message to the user (error or warning). In case of many messages there is a priority rule. First shows error message, if all of them are solved - then warnings.
 In case of many error (or warning messages) - first message will be shown.  
 
#### Addons
  ![The example of addons](/img/widget_autocomplete_addons_example.png)
  
  Let's have a look at this example as it perfectly illustrates what you can achieve with `addons` field. If you need 
  to inject some React component in the left part of input field with suggestions, it can be achieved with that property. 
  
  You can asks why we have it along with `renderInput` property, that's how we see it:
  
  * if you need to customize input field completely - use `renderInput`
  * if you need to add a component along with input field use `addons`
  * if you need to customize input field and also add an additional component along with it - use both fields
  
  How it looks in the code:
  
  ```js
    import userInputImg from '../../images/user-input-grey.svg';
    ...
  
    <XlReactWidgetAutocomplete
    addons={
        <XlReactWidgetInputAddonGroup>
            <XlReactWidgetInputAddon>
                <img alt={'img'} src={userInputImg}/>
            </XlReactWidgetInputAddon>
            <XlReactWidgetInputAddon>
                2nd addon
            </XlReactWidgetInputAddon>
        </XlReactWidgetInputAddonGroup>
    }
    ...
/>
  ```

#### Validators
   Validators are required to check whether the specified value conforms with certain rules. 
   There is one default validator exists when `required` field is set as `true`. Others can be created by user and 
   specified via `validators` field. 
   
   Structure of the validator looks like this:
   
   ```
        getInvalidDateValidator = (model) => {
            const message = {
                show: true,
                text: 'Example: Dec 1, 2018',
                type: ERROR
            };
    
            const condition = model && !this.toMoment(model).isValid();
            return {condition, message};
        };
   ```
   
   So as you can see, function should return back an object with 2 required fields. If `condition` equals `true` that 
   means that the component has a problem. The reason of the problem is described in the `message`. If you want to 
   show to the user a message, `show` has to be `true`. If type is `ERROR` it will be highlighted in red color and if 
   `WARNING` - orange. Field `text` contains the message will be displayed to the user.
   
   
#### Sub Actions
  ![The example of sub actions](/img/widget_autocomplete_with_subactions.png)
  
  Subactions will take the first line in the suggestion list. If there will be multiple of them, they will be 
  stacked in a row. You can define:
   * _label_ for each action, which will be displayed
   * _action_ which will be executed when user will click on that action
   * _disabled_ if you want to restrict executing of action based on some conditions
   
   
   ```js
    subActions: [
        {
            action: this.open,
            label: 'Open'
        },
        {
            action: this.edit,
            label: 'Edit'
        }
    ]
```


#### Suggestion Behavior
   Component allows you to control a certain behavior characteristics of it. If nothing is specified the default behavior 
   is applied.
   
   Let's see what is happening by default and what structure of object you can apply here:
   
   ```javascript
export const defaultSuggestionBehavior = {
    handleOnFocus: R.curry((component, event) => {
        /* 
           There are 2 options here even for default behavior.
            * Just propagate onFocus event on input field
            * Propagate and show all suggestions by cleaning currently typed value in the component.
              That will happen only if component wasn't in focused state. That will help in a situation, if you 
              for example clicked in input field, then started typing and clicked there again. So then nothing will 
              happen, you still will preserve typed data.
        */
    }),
    handleOnSuggestionClick: R.curry((component, event, suggestion) => {
        /**
        * It propagates event `handleSuggestionSelected(event, {suggestion});` And updates the list of suggestions. 
        */      
    }),
    renderSuggestion: R.curry((component, data, value) => {
        /**
        * Renders default view of suggestion item. 
        */
    })
};
```

xl-react-widget-tags component is based on this component and applies on `suggestionBehavior`, so you can find there a 
good example how it can be overriden and why.
 
### Examples

The simplest working example is:

```js

const autocompleteElements = R.map((ind) => ({
    id: `Item${ind}`,
    type: ind
}), R.range(1, 7));

const transformItem = (item, objLabel) => R.is(Object, item) && objLabel ? item[objLabel] : item;

const transformItemOr = (defaultValue, item, objLabel) => {
    return transformItem(item, objLabel) || '';
};

const autocompleteHandler = ({value}) => {
    const term = transformItemOr('', value, 'id');
    const filterCond = (item) => R.toLower(item.id).indexOf(R.toLower(term)) !== -1;
    const res = R.pipe(
        R.filter(filterCond),
        R.sortBy(
            R.compose(
                R.toLower,
                R.prop('id')
            )
        )
    )(autocompleteElements);
    return Promise.resolve(res);
};

const metadata = {
    label: 'Autocomplete',
    placeholder: 'autocomplete placeholder',
    required: true,
    requiredText: 'Custom required error message overrides!'
};

const autocompleteHandlers = {addCandidates: autocompleteHandler};

<XlReactWidgetAutocomplete
    handlers={autocompleteHandlers}
    metadata={metadata}
    objLabel={'id'}
```

This example provides a sorting of suggestions and ability to search them when you start typing inside of input field. 
