Search code examples
timetimerfunctional-programmingelm

How can I add a downward counting timer to my Elm page?


I'm pretty new to Elm and I've been trying to make a quiz while struggling really hard. What I need is a timer that counts downwards from 10 to 1 and once it hits 1 it switches to another page. I've tried using the time example from Elm's site as well as the Elm-timer library but all without success.

The code I'm working with:

 module QuizPage exposing (..)

import Browser
import Browser.Navigation as Nav
import Html exposing (..)
import Html.Attributes exposing (..)
import Url
import Html.Events exposing (..)



-- MAIN


main : Program () Model Msg
main =
  Browser.application
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    , onUrlChange = UrlChanged
    , onUrlRequest = LinkClicked
    }



-- MODEL


type alias Model =
  { key : Nav.Key
  , url : Url.Url
  , uporabnik : String
  , igra : Int
  }


init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init flags url key =
  ( Model key url "" 0, Cmd.none )



-- UPDATE


type Msg
  = LinkClicked Browser.UrlRequest
  | UrlChanged Url.Url
  | SpremembaImena String


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
  case msg of
    LinkClicked urlRequest ->
      case urlRequest of
        Browser.Internal url ->
             ( model, Nav.load (Url.toString url) )


        Browser.External href ->
          ( model, Nav.load href )

    UrlChanged url ->
      ( { model | url = url }
      , Cmd.none
      )

    SpremembaImena ime ->
      ({model | uporabnik = ime}, Cmd.none)


-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions _ =
  Sub.none



-- VIEW



view : Model -> Browser.Document Msg
view model =
    {
     title = "Kviz"
     , body =
        [div [style "width" "100%",  style "text-align" "center", style "background-color" "powderblue", style "position" "fixed", style "width" "100%", style "height" "100%"]
        [ Html.br[][]
        , Html.div [style "width" "100%", style "font-size" "20px"][ Html.div[][Html.text "Koda vaše igre: 1234"], Html.div [][Html.text "Čas do konca 7s"] ]
        , Html.br [][]
        , Html.br [][]
        , Html.br [][]
        , Html.br [][]
        , div [style "font-size" "30px"][Html.text "Vprašanje"]
        , Html.br [][]
        , Html.br [][]
        , Html.br [][]
        , Html.br [][]
        , Html.div [ style "margin-left" "43%" ][ viewLink "EndPage.elm" "Odgovor1"]
        , Html.br [][]
        , Html.br [][]
        , Html.div [ style "margin-left" "43%"][ viewLink "EndPage.elm" "Odgovor2"]
        , Html.br [][]
        , Html.br [][]
        , Html.div [ style "margin-left" "43%" ][ viewLink "EndPage.elm" "Odgovor3"]
        , Html.br [][]
        , Html.br [][]
        , Html.div [ style "margin-left" "43%" ][ viewLink "EndPage.elm" "Odgovor4"]
        ]]
    }


viewLink : String -> String -> Html msg
viewLink path name =
   a [ href path , style "text-decoration" "none", style "color" "black", style "width" "200px", style "magin-left" "200px", style "display" "block", style "font" "bold 11px Arial", style "border-top" "1px solid #CCCCCC", style "text-decoration" "none", style "background-color" "#EEEEEE", style "color" "#333333", style "padding" "2px 6px 2px 6px", style "border-right" "1px solid #CCCCCC", style "border-bottom" "1px solid #CCCCCC", style "border-left" "1px solid #CCCCCC", style "align" "center" ] [ text name ] 

Any help is highly appreciated!


Solution

  • The answer to my question is a simple countdown timer.

    ELM:

    module Main exposing (..)
    
    import Browser
    import Html exposing (..)
    import Task
    import Time
    
    -- MAIN
    
    main =
      Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
    
    -- MODEL
    
    type alias Model =
      { 
       cas : Int
      }
    
    init : () -> (Model, Cmd Msg)
    init _ =
      ( Model  10, Cmd.none
      )
    
    -- UPDATE
    
    type Msg
      = Tick Time.Posix
    
    update : Msg -> Model -> (Model, Cmd Msg)
    update msg model =
      case msg of
        Tick newTime ->
          if model.cas == 0 then
             ( { model | cas = 0 }
             , Cmd.none
             ) 
          else
             ( { model | cas = (racun model) }
             , Cmd.none
             )
    
    -- SUBSCRIPTIONS
    
    subscriptions : Model -> Sub Msg
    subscriptions model =
      Time.every 1000 Tick
    
    racun : Model -> Int 
    racun model =
       model.cas - 1
    
    -- VIEW
    
    view : Model -> Html Msg
    view model =
      let
        first = String.fromInt (model.cas)
      in
      h1 [] [ text (first) ]
    

    HTML:

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