futureworkz/elm-autocomplete/1.0.1

NOTE: the latest version is 1.0.2

Autocomplete

Autocomplete contains the main logic to handle auto-complete. The state and logic of Autocomplete should reside within your model. Please refer to our examples to see how it all linked up.

To render the Autocomplete, please refer to Autocomplete.View or Autocomplete.Styled.

Types

Opaque type of Autocomplete state

type alias Msg a =
Msg a

Opaque type of Autocomplete internal msg

type alias Choices a =
Choices a

Record to hold the query and choices for your fetcher function.

type alias Choices a =
    { query : String
    , choices : List a
    , ignoreList : List a
    }


fetcher : Autocomplete.Choices String -> Task String (Autocomplete.Choices String)
fetcher lastChoices =
    let
        dogs =
            [ "Hunter"
            , "Polo"
            , "Loki"
            , "Angel"
            , "Scout"
            , "Lexi"
            , "Zara"
            , "Maya"
            , "Baby"
            , "Bud"
            , "Ella"
            , "Ace"
            , "Kahlua"
            , "Jake"
            , "Apollo"
            , "Sammy"
            , "Puppy"
            , "Gucci"
            , "Mac"
            , "Belle"
            ]


        insensitiveStringContains : String -> String -> Bool
        insensitiveStringContains a b =
            String.contains (String.toLower a) (String.toLower b)


        choiceList : List String
        choiceList =
            if String.length lastChoices.query == 0 then
                []


            else
                List.filter (insensitiveStringContains lastChoices.query) dogs
    in
    Task.succeed { lastChoices | choices = choiceList }
type alias ViewState a =
{ query : String
, choices : List a
, ignoreList : List a
, selectedIndex : Maybe Int
, status : ViewStatus
}

Record to expose common values of Autocomplete to be used for display

= NotFetched
| Fetching
| Error String
| FetchedChoices

A useful union type for rendering the correct view for each state of Autocomplete

State Management

init : Choices a -> (Choices a -> Task String (Choices a)) -> Autocomplete a

Initialize the Autocomplete state with your fetcher function

init : ( Model, Cmd Msg )
init =
    ( { -- Initialize the Autocomplete state
        autocompleteState = Autocomplete.init { query = "", choices = [], ignoreList = [] } fetcher
      , selectedValue = Nothing
      }
    , Cmd.none
    )


fetcher : Autocomplete.Choices String -> Task String (Autocomplete.Choices String)
fetcher lastChoices =
    let
        dogs =
            [ "Hunter"
            , "Polo"
            , "Loki"
            , "Angel"
            , "Scout"
            , "Lexi"
            , "Zara"
            , "Maya"
            , "Baby"
            , "Bud"
            , "Ella"
            , "Ace"
            , "Kahlua"
            , "Jake"
            , "Apollo"
            , "Sammy"
            , "Puppy"
            , "Gucci"
            , "Mac"
            , "Belle"
            ]


        insensitiveStringContains : String -> String -> Bool
        insensitiveStringContains a b =
            String.contains (String.toLower a) (String.toLower b)


        choiceList : List String
        choiceList =
            if String.length lastChoices.query == 0 then
                []


            else
                List.filter (insensitiveStringContains lastChoices.query) dogs
    in
    Task.succeed { lastChoices | choices = choiceList }
update : Msg a -> Autocomplete a -> ( Autocomplete a, Cmd (Msg a) )

Updates the Autocomplete state

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        -- This is the main wire-up to pass Autocomplete Msg to Autocomplete state
        OnAutocomplete autocompleteMsg ->
            let
                ( newAutocompleteState, autoCompleteCmd ) =
                    Autocomplete.update autocompleteMsg model.autocompleteState
            in
            ( { model | autocompleteState = newAutocompleteState }
            , Cmd.map OnAutocomplete autoCompleteCmd
            )


-- ...

Helpers

reset : Choices a -> Autocomplete a -> Autocomplete a

Reset the Autocomplete State

There are many scenarios Autocomplete can handle using the reset.

On selected value, display selectedValue but remove all choices:

Autocomplete.reset
    { query = Maybe.withDefault query selectedValue
    , choices = []
    , ignoreList = []
    }
    autocompleteState

On selected multiple values, ignore selected values but still display the choices:

Autocomplete.reset
    { query = ""
    , choices = Autocomplete.choices autocompleteState
    , ignoreList = selectedValueList
    }
    autocompleteState

Returns the selectedValue

Accessors

viewState : Autocomplete a -> ViewState a

Returns the ViewState of the Autocomplete to render the view. Remember to attach Autocomplete events to your view! See Autocomplete.View

query : Autocomplete a -> String

Returns the query of the Autocomplete

choices : Autocomplete a -> List a

Returns the current list of choices

selectedIndex : Autocomplete a -> Maybe Int

Returns the selected index of the Autocomplete

isSelected : Maybe Int -> Int -> Bool

Helper function to calculate if an index is selected

renderChoice : (Int -> List (Attribute Msg)) -> Maybe Int -> Int -> String -> Html Msg
renderChoice events selectedIndex index s =
    Html.div
        (if Autocomplete.isSelected selectedIndex index then
            Html.Attributes.style "backgroundColor" "#EEE" :: events index


         else
            Html.Attributes.style "backgroundColor" "#FFF" :: events index
        )
        [ Html.text s ]