2015-08-09 14 views

risposta

40

La funzione focus nel pacchetto elm-lang/dom viene utilizzato per impostare fuoco con una Task (senza usare port s o JavaScript).

Internamente utilizza requestAnimationFrame per garantire il rendering di tutti i nuovi aggiornamenti DOM prima di cercare il nodo DOM su cui concentrarsi.

Un esempio di utilizzo:

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 

Full example on Ellie

+0

Nota, questa * * fa il lavoro, ma ho trovato che può fallire in modo silenzioso, a volte inaspettati se si aggiunge dinamicamente l'elemento. – AdrianoFerrari

+0

Hai un esempio in cui ciò non riesce? – robertjlooby

+0

Purtroppo, non ho un esempio riproducibile in questo momento. Ti posterò se trovo un altro. Nel complesso, questo è sicuramente il modo giusto per farlo, quindi il mio commento dovrebbe essere ignorato fino a quando non riesco a trovare un caso specifico :) – AdrianoFerrari

4

Ho passato un po 'di tempo ad esplorarlo di recente. Sfortunatamente, non penso sia possibile con la libreria esistente elm-html. Tuttavia, mi sono imbattuto in un hack che utilizza le animazioni CSS per attivare un evento e incorporarlo in puro js.

Ecco la mia modifica su Elm utilizzando un nodo script e un nodo style. È molto brutto secondo me.

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 
""" 
9

Una soluzione per questo è di usare Mutation Observers. Inserire questo JavaScript sia nella pagina HTML principale o nella vista principale del codice 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); 
    } 
    } 
} 

Poi creare elementi HTML includendo Html.Attributes.attribute "data-autofocus" "".

Problemi correlati