uuba
uuba

Reputation: 13

Elm - updating the model based on values in a signal

I am using a port to pass an object from javascript to elm, and I want to update my model based on the value received from JS. Heres my code:

    type alias Model = { x: String, y: String }
    type Action = Received { x: String, y: String }
    update : Action -> Model -> Model
    update action model =
        case action of
            Received rec -> { model | x = rec.x, y = rec.y }

    port rec : Signal { x: String, y: String }
    result = Signal.map update (Received rec)

However, I get a type mismatch compiler error on the last line, saying that update is receiving an argument of type Signal { x: String, y: String } when it should be receiving { x: String, y: String }

Upvotes: 1

Views: 324

Answers (1)

lukewestby
lukewestby

Reputation: 1207

So it looks like what you'd like to do is go from a Signal of incoming records from your port to a Signal of the current state of your model. There was mention of foldp in the comments, and it'll come into play so I'll be sure to address it. In order to get a Signal of the current model state from your port, this is what your code could look like:

initialModel : Model
initialModel =
  { x = "0"
  , y = "0"
  }

result : Signal Model
result =
  rec
    |> Signal.map Received
    |> Signal.foldp update initialModel

Let's go over this one step at a time now.

initialModel : Model
initialModel =
  { x = "0"
  , y = "0"
  }

With this assignment we set up an initial state from which to proceed. Elm's Signals must always have an initial value, regardless of whether that initial value is relevant to your program. If you don't care what your initial model is, you can assign the record's fields to be whatever you'd like.

result : Signal Model
result =
  rec
    |> Signal.map Received
    -- ...

Here we use Signal.map to go from the { x : String, y : String } records coming from your port to a Signal of Actions, namely, the Recieved action. So at this stage we have a Signal Action.

|> Signal.foldp update initialModel

In this final step we take that Signal Action from the previous step and fold it into the previous model with Signal.foldp. The first argument is a function that accepts some type a representing incoming new values from another Signal (in this case it's our Signal Action), and the last available value of our state (which is initialModel at the outset and then the last return value of update going forward) and returns the next state. This is how any statefulness is acquired in an Elm application.

result ends up as the Signal for the most recent incarnation of the application's model, which you can then map on to a Signal of Html or Graphics.Element or whatever you'd like using Signal.map again in order to produce some user interface that reacts to updates in your application.

Upvotes: 1

Related Questions