Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elm - How Do I Detect Current Focus

Tags:

elm

How do you get the current focus in Elm? I know how to set focus with Elm, but I can't find any functionality to detect what currently has focus.

like image 477
G4143 Avatar asked May 12 '17 03:05

G4143


1 Answers

The elm-lang/dom package allows setting focus on an element given an ID but it does not allow you to fetch the currently focused element. It hints that you can use document.activeElement for this. To do that, you'll have to use ports.

Here is a contrived example. Let's say you have a Model that contains the currently selected id and a list of all ids of some textboxes we'll soon create.

type alias Model =
    { selected : Maybe String
    , ids : List String
    }

The Msgs we will use will be able to inquire about the focus as well as use the Dom library to set focus:

type Msg
    = NoOp
    | FetchFocused
    | FocusedFetched (Maybe String)
    | Focus (Maybe String)

For that, we will need two ports:

port focusedFetched : (Maybe String -> msg) -> Sub msg

port fetchFocused : () -> Cmd msg

The javascript calling these ports will report on the current document.activeElement:

var app = Elm.Main.fullscreen()
app.ports.fetchFocused.subscribe(function() {
  var id = document.activeElement ? document.activeElement.id : null;
  app.ports.focusedFetched.send(id);
});

The view displays the currently selected id, provides a list of buttons that will set the focus on one of the numbered textboxes below.

view : Model -> Html Msg
view model =
    div []
        [ div [] [ text ("Currently selected: " ++ toString model.selected) ]
        , div [] (List.map viewButton model.ids)
        , div [] (List.map viewInput model.ids)
        ]


viewButton : String -> Html Msg
viewButton id =
    button [ onClick (Focus (Just id)) ] [ text id ]


viewInput : String -> Html Msg
viewInput idstr =
    div [] [ input [ id idstr, placeholder idstr, onFocus FetchFocused ] [] ]

The update function ties it all together:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        NoOp ->
            model ! []

        FetchFocused ->
            model ! [ fetchFocused () ]

        FocusedFetched selected ->
            { model | selected = selected } ! []

        Focus (Just selected) ->
            model ! [ Task.attempt (always NoOp) (Dom.focus selected), fetchFocused () ]

        Focus Nothing ->
            { model | selected = Nothing } ! [ fetchFocused () ]

Here is a working example on ellie-app.com.

like image 136
Chad Gilbert Avatar answered Oct 04 '22 09:10

Chad Gilbert