Change View from Model -> Browser.Document Msg to Model -> Html Msg

hello,
I code RPN calculator which take API URL and calculate Json when receive it.
my code

module Main exposing (..)

import Browser
import Html exposing (Html, div, input, text)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import Http
import Json.Decode exposing (list, string)
import Html exposing (output)


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



-- Types


type Operator
    = Minus
    | Plus
    | Mult
    | Div


type ValidTerm
    = Op Operator
    | Integer Int
    | Url String


type Msg
    = GotInput String
    | GotParsed (Result String (List ValidTerm))
    | GotJson String (Result Http.Error String)
    | GotOutput String


inputMsg : String -> Msg
inputMsg s =
    GotInput s


type alias Model =
    { input : String
    , parsed : Result String (List ValidTerm)
    , output : String
    }



-- Elm architecture


init : flags -> ( Model, Cmd msg )
init _ =
    ( { input = "", parsed = Err "Empty", output = "ERROR" }, Cmd.none )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    let
        ( m, l ) =
            updateAux msg model []
    in
    ( m, Cmd.batch l )


updateAux : Msg -> Model -> List (Cmd Msg) -> ( Model, List (Cmd Msg) )
updateAux msg model cmds =
    case msg of
        GotInput input ->
            let
                new_model =
                    { model | input = input }
            in
            updateAux (GotParsed (parseJson ("[\"" ++ new_model.input ++ "\"]"))) new_model cmds

        GotParsed parsed ->
            let
                new_model =
                    { model | parsed = parsed }
            in
            let
                output =
                    evaluate new_model.parsed

                cmds_ =
                    getUrlsCmds new_model.parsed
            in
            updateAux (GotOutput output) new_model (cmds_ ++ cmds)

        GotJson url json ->
            let
                parsedSubTerm =
                    replaceUrl url json model.parsed
            in
            updateAux (GotParsed parsedSubTerm) model cmds

        GotOutput output ->
            ( { model | output = output }, cmds )


view : Model -> Browser.Document Msg
view model =
    { title = "Polish notation calculator"
    , body =
        [ viewInput "text" "input" model.input inputMsg
        , viewOutput "output" model.output
        ]
    }


viewInput : String -> String -> String -> (String -> msg) -> Html msg
viewInput t p v toMsg_ =
    input [ type_ t, id p, value v, onInput toMsg_ ] []


viewOutput : String -> String -> Html msg
viewOutput p v =
    output [ id p ] [ text v ]


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



-- Helpers


parseJson : String -> Result String (List ValidTerm)
parseJson input =
    case Json.Decode.decodeString (Json.Decode.list string) input of
        Ok v ->
            decodeNreverse v []

        Err e ->
            Err ("Failed to parse" ++ input)


decodeNreverse : List String -> List ValidTerm -> Result String (List ValidTerm)
decodeNreverse input acc =
    case input of
        [] ->
            Ok acc

        x :: xs ->
            case toValidTerm x of
                Ok t ->
                    decodeNreverse xs (t :: acc)

                Err e ->
                    Err e


toValidTerm : String -> Result String ValidTerm
toValidTerm s =
    case String.toInt s of
        Nothing ->
            case s of
                "+" ->
                    Ok (Op Plus)

                "-" ->
                    Ok (Op Minus)

                "/" ->
                    Ok (Op Div)

                "*" ->
                    Ok (Op Mult)

                _ ->
                    Ok (Url s)

        Just i ->
            Ok (Integer i)


evaluate : Result String (List ValidTerm) -> String
evaluate resultTerms =
    case resultTerms of
        Ok terms ->
            case evaluateAux (List.reverse terms) [] of
                Ok i ->
                    String.fromInt i

                Err e ->
                    "ERROR"

        Err e ->
            "ERROR"


evaluateAux : List ValidTerm -> List ValidTerm -> Result String Int
evaluateAux t acc =
    case t of
        [] ->
            case acc of
                [ Integer i ] ->
                    Ok i

                [ Op _ ] ->
                    Err "Operator in accumulator"

                _ ->
                    Err ("Too many elements in accumulator" ++ vstoString acc)

        x :: xs ->
            case x of
                Integer i ->
                    evaluateAux xs (x :: acc)

                Op o ->
                    case acc of
                        first :: second :: tail ->
                            case [ first, second ] of
                                [ Integer t1, Integer t2 ] ->
                                    evaluateAux xs (Integer (calc o t1 t2) :: tail)

                                _ ->
                                    Err "Weird operands"

                        _ ->
                            Err (vstoString acc)

                Url u ->
                    Err "Bad url or not yet arrived"


calc : Operator -> Int -> Int -> Int
calc op t1 t2 =
    case op of
        Plus ->
            t1 + t2

        Minus ->
            t1 - t2

        Mult ->
            t1 * t2

        Div ->
            t1 // t2


vtoString : ValidTerm -> String
vtoString t =
    case t of
        Op Plus ->
            "+"

        Op Minus ->
            "-"

        Op Div ->
            "/"

        Op Mult ->
            "*"

        Integer i ->
            String.fromInt i

        Url u ->
            u


vstoString : List ValidTerm -> String
vstoString l =
    case l of
        [] ->
            ""

        x :: xs ->
            vtoString x ++ vstoString xs


getUrlsCmds : Result String (List ValidTerm) -> List (Cmd Msg)
getUrlsCmds resultTerms =
    case resultTerms of
        Ok t ->
            getUrlsCmdsAux t []

        Err _ ->
            []


getUrlsCmdsAux : List ValidTerm -> List (Cmd Msg) -> List (Cmd Msg)
getUrlsCmdsAux terms acc =
    case terms of
        [] ->
            acc

        x :: xs ->
            case x of
                Url u ->
                    getUrlsCmdsAux xs (Http.get { url = u, expect = Http.expectString (GotJson u) } :: acc)

                _ ->
                    getUrlsCmdsAux xs acc


replaceUrl : String -> Result Http.Error String -> Result String (List ValidTerm) -> Result String (List ValidTerm)
replaceUrl url json parsed =
    case parsed of
        Ok p ->
            case json of
                Ok j ->
                    case parseJson j of
                        Ok t ->
                            Ok (replaceUrlAux url t p [])

                        Err e ->
                            Err e

                Err e ->
                    Err "Bad http request"

        Err e ->
            Err e


replaceUrlAux : String -> List ValidTerm -> List ValidTerm -> List ValidTerm -> List ValidTerm
replaceUrlAux url termsFromUrl parsed acc =
    case parsed of
        [] ->
            List.reverse acc

        x :: xs ->
            case x of
                Url u ->
                    if u == url then
                        replaceUrlAux url termsFromUrl xs (termsFromUrl ++ acc)

                    else
                        replaceUrlAux url termsFromUrl xs (x :: acc)

                _ ->
                    replaceUrlAux url termsFromUrl xs (x :: acc)

i want view to be like that

view : Model -> Html Msg
view model =
    div []
         [ input [ type_ "string", id "input",placeholder "Enter polish", value model.input, onInput Setvalue] []
        , br [] []
        , output [ id "output", value <| model.output ]
        []
        ]

can you please help, thank youu

The Browser.document function in main requires the view function to return a Document msg. This way you can control the page’s title by setting the title field on the record you are returning from your view function.

If you don’t want to control the title you can switch from Browser.document to Browser.element instead.

I want to switch to

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

If you use Browser.sandbox you cannot use commands. You likely want Browser.element as suggested by @Jayshua above:

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

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.