futureworkz / elm-autocomplete / 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


type Autocomplete a

Opaque type of Autocomplete state


type alias Msg a =
Internal.Msg a

Opaque type of Autocomplete internal msg


type alias Choices a =
Internal.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 Basics.Int
, status : ViewStatus 
}

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


type ViewStatus
    = 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, Platform.Cmd.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

selectedValue : Autocomplete a -> Maybe a

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 Basics.Int

Returns the selected index of the Autocomplete

isSelected : Maybe Basics.Int -> Basics.Int -> Basics.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 ]