LoginSignup
4
1

More than 5 years have passed since last update.

elm 0.19 で JSONを使ってjsと通信したメモ

Posted at

概要

前回は入力と表示を同じファイルにしていたが、分けてみる。

ファイル

  • subscribeで、 Elm -> javascript
  • sendで、javascript -> Elm
app/src/card.js
'use strict';

require("./styles.scss");

const handouts = require('./Card/Main');
const creator = require('./Card/HandoutCreator');

const handoutsApp = handouts.Elm.Main.init({flags: 0, node: document.getElementById('cards')});
const creatorApp = creator.Elm.Main.init({flags: null, node: document.getElementById('cardCreator')});

creatorApp.ports.toJs.subscribe(data => {
  const json = JSON.stringify(data);
  handoutsApp.ports.fromJs.send(json);
})
  • port moduleでportを使うモジュールを明示
  • subscriptionsにメッセージを登録
  • updateでjsonをモデルにデコード
app/src/Card/Main.elm
port module Main exposing (main)

import Browser
import Card.HandoutList as HandoutList
import Card.InputModel
import Html exposing (..)
import Html.Attributes exposing (..)
import Json.Decode



-- In ports


port fromJs : (String -> msg) -> Sub msg


main : Program Int Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , view = view
        , subscriptions = \_ -> Sub.batch [ fromJs FromJs ]
        }



-- model


type alias Model =
    { inputModel : Card.InputModel.Model
    , handoutListModel : HandoutList.Model
    }


initialModel : Model
initialModel =
    { inputModel = Card.InputModel.initialModel
    , handoutListModel = HandoutList.initialModel
    }


init : Int -> ( Model, Cmd Msg )
init flags =
    ( initialModel, Cmd.none )


type Msg
    = HandoutListMsg HandoutList.Msg
    | FromJs String



-- update


update : Msg -> Model -> ( Model, Cmd Msg )
update message model =
    case message of
        HandoutListMsg subMsg ->
            let
                ( updatedHandoutListModel, handoutListCmd ) =
                    HandoutList.update subMsg model.inputModel.title model.handoutListModel
            in
            ( { model | handoutListModel = updatedHandoutListModel }, Cmd.map HandoutListMsg handoutListCmd )

        FromJs json ->
            let
                r =
                    Json.Decode.decodeString Card.InputModel.decoder json

                -- decodeに成功したら、InputModelを。失敗したら元の値を返す。
                im =
                    case r of
                        Ok m ->
                            m

                        Err _ ->
                            model.inputModel
            in
            ( { model | inputModel = im }, Cmd.none )



-- subscription


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



-- view


view : Model -> Html Msg
view model =
    div [ class "container" ]
        [ Html.map HandoutListMsg (HandoutList.view model.handoutListModel)
        ]

  • jsonにエンコードしてjavascriptに送信
app/src/Card/HandoutCreator.elm
port module Main exposing (main)

import Browser
import Card.InputModel exposing (Model, encode)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick, onInput)
import Json.Encode


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


main : Program (Maybe String) Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , view = view
        , subscriptions = \_ -> Sub.none
        }


init : Maybe String -> ( Model, Cmd Msg )
init flags =
    ( Card.InputModel.initialModel, Cmd.none )


type Msg
    = NoOp
    | UpdateInput String



-- update


update : Msg -> Model -> ( Model, Cmd Msg )
update message model =
    case message of
        NoOp ->
            Tuple.pair model Cmd.none

        UpdateInput s ->
            let
                newModel =
                    { model | title = s }
            in
            Tuple.pair newModel (toJs (encode newModel))



-- view


view : Model -> Html Msg
view model =
    div []
        [ handoutInput model
        ]


handoutInput : Model -> Html Msg
handoutInput model =
    Html.form []
        [ label [ attribute "for" "inputTitle" ]
            [ text "タイトル"
            ]
        , input [ attribute "type" "text", id "inputTitle", class "browser-default", onInput UpdateInput, value model.title ] []
        ]

  • デコーダーとエンコードの定義
app/src/Card/InputModel.elm
module Card.InputModel exposing (Item, Model, decoder, encode, initialModel)

import Json.Decode as D
import Json.Encode as E


type alias Item =
    String


type alias Model =
    { title : Item
    }


initialModel : Model
initialModel =
    { title = ""
    }


encode : Model -> E.Value
encode m =
    E.object
        [ ( "title", E.string m.title )
        ]


decoder : D.Decoder Model
decoder =
    D.map Model
        (D.field "title" D.string)

参考

ElmとJavaScriptの会話(Port)
elm/json
result

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1