Skip to content

Unused port call breaks subscriptions #1141

@maxhille

Description

@maxhille

I was hunting down a weird issue in one of our apps and came up with what I think it an Elm bug. In the following minimal example (also at https://ellie-app.com/p3n2dB2JKtJa1), the ping count should be the same as the pong count.

Please notice the comments in init and also in the JS code.

I think this might be the same underlying issue as #1128 and thus a regression from the changes in elm/core-1.0.{3,4,5}

port module Main exposing (main)

import Browser
import Html exposing (Html, button, div, p, text)
import Html.Attributes exposing (id)
import Html.Events exposing (onClick)


port ping : () -> Cmd msg


port pong : (() -> msg) -> Sub msg


type alias Model =
    { subscribed : Bool
    , pings : Int
    , pongs : Int
    }


type Msg
    = SubscribeAndPing
    | Pong ()


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


init : () -> ( Model, Cmd Msg )
init _ =
    let
        -- remove unused assignment to fix the program
        _ =
            ping ()
    in
    ( { subscribed = False
      , pings = 0
      , pongs = 0
      }
    , Cmd.none
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SubscribeAndPing ->
            ( { model | subscribed = True, pings = model.pings + 1 }
            , ping ()
            )

        Pong _ ->
            ( { model | pongs = model.pongs + 1 }, Cmd.none )


view : Model -> Html Msg
view model =
    div []
        [ button [ onClick SubscribeAndPing ] [ text "ping" ]
        , if model.subscribed then
            div []
                [ p [] [ text <| String.fromInt model.pings ++ " pings sent" ]
                , p [] [ text <| String.fromInt model.pongs ++ " pongs received" ]
                ]

          else
            p [] [ text "push button to subscribe to port and ping" ]
        ]


subscriptions : Model -> Sub Msg
subscriptions model =
    if model.subscribed then
        pong Pong

    else
        Sub.none
<html>
<head>
  <style>
    /* you can style your program here */
  </style>
</head>
<body>
  <main></main>
  <script>
    var app = Elm.Main.init({ node: document.querySelector('main') })


    app.ports.ping.subscribe(() => {
      // workaround seems to be wrapping the "send" in a requestAnimationFrame()
      // requestAnimationFrame(() => { app.ports.pong.send(null) })
       app.ports.pong.send(null)
    })
  </script>
</body>
</html>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions