phoenix_form_awesomplete v0.1.1 PhoenixFormAwesomplete

PhoenixFormAwesomplete is a Phoenix form helper that utilizes Lea Verou’s autocomplete / autosuggest / typeahead / inputsearch Awesomplete widget.

It comes with an AwesompleteUtil javascript library which adds the following features:

  • Dynamic remote data loading; based on what is typed-in it performs an ajax lookup.
  • Allow HTML markup in the shown items. Show value with description. Optionally search in the description text.
  • Show when there is an exact match.
  • Show when there isn’t a match.
  • When there is an exact match show related data (supplied in the remote data) in other parts of the page.
  • Select the highlighted item with the tab-key.

Example

iex> PhoenixFormAwesomplete.awesomplete(:user, :drinks,
...> ["data-list": "beer, gin, soda, sprite, water, vodga, whine, whisky"], 
...> %{ minChars: 1 } )
{:safe,
 ["<input data-list=\"beer, gin, soda, sprite, water, vodga, whine, whisky\"" <>
  " id=\"user_drinks\" name=\"user[drinks]\" type=\"text\">", 
  "<script>AwesompleteUtil.start('#user_drinks', {}, {minChars: 1});</script>"]}

The first three parameters are passed on unchanged to the Phoenix form text_input which generates the input tag. minChars is an option for the Awesomplete object which is started with inline javascript. Just adding the multiple option changes the generated javascript code completely, the PhoenixFormAwesomplete module takes care of that. Instead of an server side generated data-list it is possible to specify an url of a JSON web service and let the client-code lookup the data list on-demand while typing. Look at the live examples with code.

It is possible to use aliases for the javascript library references in the generated code via the environment variables util and awesomplete. The default names, AwesompleteUtil and Awesomplete respectively, are a bit long. This can shorten the average page size. For example use this javascript:

 var AU = AwesompleteUtil, AW = Awesomplete; 

and change the variables via the application config:

 :phoenix_form_awesomplete, util:         "AU"
 :phoenix_form_awesomplete, awesomplete:  "AW"

After changing the config/config.exs run:

 touch deps/phoenix_form_awesomplete/mix.exs
 mix deps.compile phoenix_form_awesomplete

Summary

Functions

This method generates an input tag and inline javascript code that starts Awesomplete

This method generates javascript code for using Awesomplete(Util)

This method generates javascript code for using Awesomplete(Util)

This method generates a script tag with javascript code for using Awesomplete(Util)

Create script tag with javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the target field

Create script tag with javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the DOM element with the given target id. The target_id can also be a javascript function. This function receives two parameters: event and dataField. The event detail property contains an array with the matching list item. The array is empty when there is no match

Create javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the DOM element with the given target id. The target_id can also be a javascript function

Create script tag with the supplied script. No defer or async because this is used for inline script

Functions

awesomplete(form, field, opts \\ [], awesomplete_opts)

This method generates an input tag and inline javascript code that starts Awesomplete.

Awesomplete options:

  • ajax - Replace ajax function. Supplied function receives these parameters: (url, urlEnd, val, fn, xhr). fn is the callback function. Default: AwesompleteUtil.ajax.
  • assign - Assign the Awesomplete object to a variable. true/false/name. If true the variable name will ‘awe_‘ + id of input tag. Default: false
  • autoFirst - Automatically select the first element. Default: false.
  • combobox - Id of the combobox button. true/false/id. If true the assumed button id is ‘awe_btn_‘ + id of the input tag. Default: false
  • convertInput - Convert input function. Internally convert input for comparison with the data list items. By default it trims the input and converts it to lowercase for a case-insensitive comparison.
  • convertResponse - Convert JSON response from ajax calls. This function is called with the parsed JSON, and allows conversion of the data before further processing. Default: nil - no conversion.
  • data - Data function as defined in Awesomplete
  • descr - Name of the field in the data list (the JSON response) that contains the description text to show below the value in the suggestion list. Default: no description
  • descrSearch - Filter must also search the input value in the description field. Default: false
  • value - Name of the field in the data list (the JSON response) that contains the value.
  • filter - Filter function as defined in Awesomplete. Mostly Awesomplete.FILTER_STARTSWITH or Awesomplete.FILTER_CONTAINS. If label is different as value, filter on value with AweompleteUtil.filterStartsWith or AwesompleteUtil.filterContains.
  • item - Item function as defined in Awesomplete. Default is to highlight all occurrences of the input text. Use AwesompleteUtil.itemStartsWith if that matches with the used filter.
  • label - Name of the field in the data list (the JSON response) that contains the text that should be shown instead of the value.
  • list - Data list as defined in Awesomplete.
  • loadall - Data list contains all items. The input value will not be used in ajax calls. Default: false
  • limit - number. If a limit is specified, and the number of items returned by the server is equal or more as this limit, the AwesompleteUtil code assumes that there are more results, so it will re-query if more characters are typed to get more refined results. The limit:1 tells that not more than 1 result is expected, so the json service doesn’t have to return an array. With limit:0 it will always re-query if more characters are typed. Default: no limit
  • maxItems - Maximum number of suggestions to display. Default: 10
  • minChars - Minimum characters the user has to type before the autocomplete popup shows up. Default: 2
  • multiple - true/false/characters. Separators to allow multiple values. If true, the separator will be the space character. Default: false
  • prepop - true/false. If true do lookup initial/autofilled value and send awesomplete-prepop event. Default: false
  • replace - Replace function as defined in Awesomplete
  • sort - Sort function as defined in Awesomplete
  • url - url for ajax calls.
  • urlEnd - Addition at the end of the url of the ajax call, after the input value.

Example

iex> PhoenixFormAwesomplete.awesomplete(:user, :eyes, ["data-list": "blue, brown, green"],
...>  %{ minChars: 1, multiple: ",;" } )
{:safe,
 ["<input data-list=\"blue, brown, green\" id=\"user_eyes\" name=\"user[eyes]\" type=\"text\">",
  "<script>AwesompleteUtil.start('#user_eyes', " <> 
  "{convertInput: function(input) {" <>
  " return input.replace(/[,;]\\s*$/, '').match(/[^,;]*$/)[0].trim().toLowerCase(); }}, " <>
  "{minChars: 1, " <> 
  "replace: function(data) {" <>
  " var text=data.value;" <> 
  " this.input.value = this.input.value.match(/^.+[,;]\\s*|/)[0] + text + ', '; }, " <>
  "filter: function(data, input) {" <>
  " return Awesomplete.FILTER_CONTAINS(data, input.match(/[^,;]*([,;]\\s*)?$/)[0]); }, " <>
  "item: function(text, input) {" <>
  " return AwesompleteUtil.itemContains(text, input.match(/[^,;]*([,;]\\s*)?$/)[0]); }});" <>
  "</script>"]}
awesomplete_js(element_id, awesomplete_opts)

This method generates javascript code for using Awesomplete(Util).

Example

iex> PhoenixFormAwesomplete.awesomplete_js('user_hobby', %{ minChars: 1 } ) 
"AwesompleteUtil.start('#user_hobby', {}, {minChars: 1});"
awesomplete_js(form, field, awesomplete_opts)

This method generates javascript code for using Awesomplete(Util).

Example

iex> PhoenixFormAwesomplete.awesomplete_js(:user, :hobby, %{ minChars: 1 } )    
"AwesompleteUtil.start('#user_hobby', {}, {minChars: 1});"
awesomplete_script(form, field, awesomplete_opts)

This method generates a script tag with javascript code for using Awesomplete(Util).

Example

iex> PhoenixFormAwesomplete.awesomplete_script(:user, :hobby, %{ minChars: 1 } )
{:safe,
 "<script>AwesompleteUtil.start('#user_hobby', {}, {minChars: 1});</script>"}
copy_to_field(source_form, source_field, data_field \\ nil, target_form, target_field)

Create script tag with javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the target field.

Example

iex> PhoenixFormAwesomplete.copy_to_field(:user, :color, "label", :door, :paint)  
{:safe,
 "<script>AwesompleteUtil.startCopy('#user_color', 'label', '#door_paint');</script>"}
copy_to_id(source_form, source_field, data_field \\ nil, target_id)

Create script tag with javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the DOM element with the given target id. The target_id can also be a javascript function. This function receives two parameters: event and dataField. The event detail property contains an array with the matching list item. The array is empty when there is no match.

Example

iex> PhoenixFormAwesomplete.copy_to_id(:user, :color, "label", "#awe-color-result") 
{:safe,
 "<script>AwesompleteUtil.startCopy('#user_color', 'label', '#awe-color-result');</script>"}
copy_to_id_js(source_form, source_field, data_field \\ nil, target_id)

Create javascript that listens to awesomplete-prepop and awesomplete-match events, and copies the data_field to the DOM element with the given target id. The target_id can also be a javascript function.

Example

iex> PhoenixFormAwesomplete.copy_to_id_js(:user, :color, "label", "#awe-color-result") 
"AwesompleteUtil.startCopy('#user_color', 'label', '#awe-color-result');"
script(script)

Create script tag with the supplied script. No defer or async because this is used for inline script.

Example

iex> PhoenixFormAwesomplete.script("alert(1);")
{:safe, "<script>alert(1);</script>"}