Comment puis-je définir le focus sur un élément Html dans Elm? J'ai essayé de définir l'attribut autofocus sur l'élément et il ne définit que le focus sur le chargement de la page.
La fonction focus
dans le package Elm-lang/dom est utilisée pour définir le focus avec un Task
(sans utiliser de port
s ou JavaScript).
En interne, il utilise requestAnimationFrame
pour garantir le rendu de toutes les nouvelles mises à jour DOM avant d'essayer de trouver le nœud DOM sur lequel se concentrer.
Un exemple d'utilisation:
type Msg
= FocusOn String
| FocusResult (Result Dom.Error ())
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
FocusOn id ->
( model, Dom.focus id |> Task.attempt FocusResult )
FocusResult result ->
-- handle success or failure here
case result of
Err (Dom.NotFound id) ->
-- unable to find dom 'id'
Ok () ->
-- successfully focus the dom
Une solution de contournement est d'utiliser Mutation Observers . Insérez ce JavaScript dans votre page HTML principale ou dans la vue principale de votre code Elm:
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
handleAutofocus(mutation.addedNodes);
});
});
var target = document.querySelector('body > div');
var config = { childList: true, subtree: true };
observer.observe(target, config);
function handleAutofocus(nodeList) {
for (var i = 0; i < nodeList.length; i++) {
var node = nodeList[i];
if (node instanceof Element && node.hasAttribute('data-autofocus')) {
node.focus();
break;
} else {
handleAutofocus(node.childNodes);
}
}
}
Créez ensuite des éléments HTML en incluant Html.Attributes.attribute "data-autofocus" ""
.
J'ai passé pas mal de temps à l'explorer récemment. Malheureusement, je ne pense pas que ce soit possible avec le Elm-html
bibliothèque. Cependant, j'ai trouvé un hack qui utilise des animations css pour déclencher un événement et l'intégrer dans des js purs.
Voici mon hack dans Elm en utilisant un nœud script
et un nœud style
. C'est très moche à mon avis.
import Html exposing (div, button, text, input, node)
import Html.Events exposing (onClick)
import Html.Attributes exposing (type', class)
import StartApp.Simple
main =
StartApp.Simple.start { model = model, view = view, update = update }
model = []
view address model =
-- View now starts with a <style> and <script> (hacky)
(node "style" [] [ Html.text style ]) ::
(node "script" [] [Html.text script ]) ::
(button [ onClick address AddInput ] [ text "Add Input" ]) ::
model |>
div []
type Action = AddInput
update action model =
case action of
AddInput -> (Html.p [] [input [type' "text", class "focus"] []]) :: model
-- Use pure string css (hacky)
style = """
.focus {
animation-name: set-focus;
animation-duration: 0.001s;
-webkit-animation-name: set-focus;
-webkit-animation-duration: 0.001s;
}
@-webkit-keyframes set-focus {
0% {color: #fff}
}
@keyframes set-focus {
0% {color: #fff}
}
"""
-- Cheating by embedding pure javascript... (hacky)
script = """
var insertListener = function(event){
if (event.animationName == "set-focus") {
event.target.focus();
}
}
document.addEventListener("animationstart", insertListener, false); // standard + firefox
document.addEventListener("MSAnimationStart", insertListener, false); // IE
document.addEventListener("webkitAnimationStart", insertListener, false); // Chrome + Safari
"""
Avec Elm/html 0,19, vous pouvez définir Html.Attrbutes autofocus sur True
input [ onInput Code, autofocus True ] []