Getting DOM value from Elm ports

My elm application uses an auto-scroll function that gets the Y position of an element and uses Dom.Scroll .toY to scroll there.

Two do this; I configure two ports; subscription and sender.

ports.elm

port setYofElementById : Maybe String -> Cmd msg
port getYofElementById : (Value -> msg) -> Sub msg

index.html

app.ports.setYofElementById.subscribe(function(id) {
  var element = document.getElementById(id);
  var rect = element.getBoundingClientRect();
  app.ports.getYofElementById.send({"number": rect.top});
})

Listener is a subscription

subscriptions : Model -> Sub Msg
subscriptions model =
    Ports.getYofElementById getYofElementById

getYofElementById : Decode.Value -> Msg
getYofElementById value =
    let
        result =
            Decode.decodeValue bSimpleIntValueDecoder value
    in
    case result of
        Ok simpleIntValue ->
            SetSelectedElementYPosition (Just simpleIntValue.number)

        Err id ->
            SetSelectedElementYPosition Nothing

SetSelectedElementYPosition just sets up the model.

Now the action that does this has two functions: call Port.setYofElementById, then scroll to the Y value in the model, assuming it is already set.

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        ScrollToY idString ->
            model
                => Cmd.batch
                    [ Ports.setYofElementById (Just idString)
                    , Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" model.selectedElementYPosition
                    ]

However, this does not occur sequentially. When the action first fires, nothing happens. If I run it again, it scrolls to the location specified in the first action. Therefore, it seems that it calls Dom.Scroll.toYbefore the value is set.

Cmd in ScrollToY ? ?

+4
2

, , , Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" model.selectedElementYPosition , , . .

subscribe send , , send js elm, , js.

, SetSelectedElementYPosition , :

    SetSelectedElementYPosition idString ->
       ({model | selectedElementYPosition = number }, Cmd.none)
            |> andThen update GoToSelectedElementYPosition
+2

Cmd , , , Dom.Scroll.toY, , , setYofElementById. :

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ScrollToY idString ->
            (model, Ports.setYofElementById idString)
        SetSelectedElementYPosition (Just newY) -> 
            (model, Task.attempt (always NoOp) <| Dom.Scroll.toY "ul" newY)
        SetSelectedElementYPosition Nothing -> 
            (model, Cmd.none)
        NoOp -> 
            (model, Cmd.none)

Cmd , newY Dom.Scroll.toY , .

+5

Source: https://habr.com/ru/post/1692491/


All Articles