Send json object to a port program

hi all,
i am learning elm and on the port program example.
i understand it but now want to send json data through the port instead of strings.
i am however confused about how to change the update function as well as change the general model from a list of strings to a list of JSON objects.
this is the paste of the code
this is the format of the model

-- MODEL


type alias Model =
  { draft : String
  , messages : List Quote
  }

type alias Quote =
  { quote : String
  , source : String
  , author : String
  , year : Int
  }

is this correct??
also is there a way to output debugging data to the elm console.
like a debug of the model in the view code.
thanks.

Debugging

In reverse order, you can log debug info with Debug.log "some label msg" data, e.g. you could in your view code write something like

view model =
    let
        _ = Debug.log "my model" model
    in

and in your browser dev tools console you’ll see

my model <your model data>

Ports

To send JSON through ports you’ll first want to install elm/json, i.e. elm install elm/json. Then you can write

import Json.Decode
import Json.Encode

port fromElm : Json.Encode.Value -> Cmd msg

port toElm : (Json.Encode.Value -> msg) -> Sub msg

-- example usage

init : () -> ( Model, Cmd Msg )
init () =
    let
        initModel = { listStr = [ "hello", "world" ] }
    in
    ( initModel
    , fromElm (Json.Encode.list Json.Encode.string initModel.listStr)
    )

subscriptions : Model -> Sub Msg
subscriptions model =
    toElm SomeMsg decodeValue

decodeValue : Json.Decode.Decoder SomeValue
decodeValue =
    -- implement decoder here for your value

Your decoder does look great btw!

1 Like

@wolfadex thanks!!.
will implement the changes and get back to you.

hi,
@wolfadex i have made some progress but running into some errors.
this is the new code.
but i am getting some errors when i try to run the code.
find below

-- TYPE MISMATCH  .../PortTest.elm

The 1st argument to `messageReceiver` is not what I expect:

85| subscriptions model = messageReceiver quoteDecoder
                                          ^^^^^^^^^^^^
This `quoteDecoder` value is a:

    Decoder msg

But `messageReceiver` needs the 1st argument to be:

    Json.Encode.Value -> msg


-- TYPE MISMATCH  .../PortTest.elm

Something is off with the body of the `quoteDecoder` definition:

106|>  map4 Quote 
107|>    (field "quote" string)
108|>    (field "source" string)
109|>    (field "author" string)
110|>    (field "year" int) 

This `map4` call produces:

    Decoder Quote

But the type annotation on `quoteDecoder` says it should be:

    Decoder msg

seems the issue is from the quotedecoder function.
i tried changing the type signature of the quotedecoder from

quoteDecoder : Json.Decode.Decoder msg

to

quoteDecoder : Json.Decode.Decoder Quote

but got a different error

-- TYPE MISMATCH  /opt/erlang/monitor_erl/monitor_erl_elm/elm_test_project/src/PortTest.elm

The 1st argument to `messageReceiver` is not what I expect:

85| subscriptions model = messageReceiver quoteDecoder
                                          ^^^^^^^^^^^^
This `quoteDecoder` value is a:

    Decoder Quote

But `messageReceiver` needs the 1st argument to be:

    Json.Encode.Value -> msg



any ideas.
thanks!!

Nice work! Looks like maybe there was a slight miscommunication between us. Your decoder should be Json.Decode.Decoder Quote and then you’ll want subscriptions model = messageReceiver Recv quoteDecoder. Hopefully that helps. If not, let me know!

thanks for the hints!.
tried it and now getting this error in the code

-- TYPE MISMATCH .../PortTest.elm

The 1st argument to `messageReceiver` is not what I expect:

85| subscriptions model = messageReceiver Recv quoteDecoder
                                          ^^^^
This `Recv` value is a:

    Quote -> Msg

But `messageReceiver` needs the 1st argument to be:

    Json.Encode.Value -> msg


-- TOO MANY ARGS  /opt/erlang/monitor_erl/monitor_erl_elm/elm_test_project/src/PortTest.elm

The `messageReceiver` function expects 1 argument, but it got 2 instead.

85| subscriptions model = messageReceiver Recv quoteDecoder
                          ^^^^^^^^^^^^^^^
Are there any missing commas? Or missing parentheses?



this is the new paste of the code.
do i need to change the signature/body of the quoteDecoder function from

quoteDecoder : Json.Decode.Decoder Quote

to something else.
thanks for help!!.

I’m so sorry! I was writing that example without actually testing it. Here is an Ellie with the fixed subscription https://ellie-app.com/mx5dmWvzSp9a1. Again, sorry for not testing my example first.

@wolfadex thanks!!.
its finally get it working thanks to the changes.
hooked it up to the web-socket js code using JavaScript and all is well.
the data is coming in from the server through the websocket and i am able to process it on the elm side.
is there some sort of way to view the flow of types through the elm code and how it transforms from as it gets to one function then another.
i get the feeling it will get easier to see as i do more stuff in elm.
is there a way to make the map4 function accept other data types or combinations of data types in the quoteDecoder function.
anyway thanks again!!.

is there some sort of way to view the flow of types through the elm code and how it transforms from as it gets to one function then another.

If you compile in debug mode (if you’re using just the Elm cli then you’d add --debug like elm make src/Main.elm --debug --output=elm.js) then you can click on the blue debug button in the bottom right of the screen and you’ll be able to see every Msg that gets sent to your update function as well as the new value of your Model after that Msg has been processed.

You can also add Debug.logs to your code. E.g. if I have a List Int and I wanted to log intermediate values I could do something like

[ 3, 6, 2, 8 ]
    |> Debug.log "initial value"
    |> List.sort
    |> Debug.log "sorted"
    |> List.filter (\n -> modBy 2 n == 0)
    |> Debug.log "odds filtered out"

and I could view those logs in the browser dev tools.

is there a way to make the map4 function accept other data types or combinations of data types in the quoteDecoder function.

Yes, though an example of what you’re trying to decode might help. The Json.Decode.oneOf might be useful, though it depends on what you’re trying to decode.

I will try the debug mode out and learn some stuff from there and the decoder also.
for the decoder i need to make the integer value float instead of an int.
so the part of the model which is an int will need to be changed to a float.

quoteDecoder : Json.Decode.Decoder Transaction
quoteDecoder =
    map4 Transaction
        (field "responsecode" string)
        (field "time" string)
        (field "tname" string)
        (field "amount" int)

can become

quoteDecoder : Json.Decode.Decoder Transaction
quoteDecoder =
    map4 Transaction
        (field "responsecode" string)
        (field "time" string)
        (field "tname" string)
        (field "amount" **float**)

thanks a lot for your help !!.

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