Recherche…


Introduction

La méthode recommandée pour structurer vos applications s'appelle «l'architecture Elm».

Le programme le plus simple est constitué d'un model enregistrement stockant toutes les données qui pourraient être mises à jour, un type d'union Msg qui définit les moyens de votre programme met à jour ces données, une fonction update à Msg view update qui prend le modèle et un Msg et retourne un nouveau modèle, et une fonction view qui prend un modèle et renvoie le code HTML que votre page affichera. Chaque fois qu'une fonction retourne un Msg , le moteur d'exécution Elm l'utilise pour mettre à jour la page.

Programme débutant

Html a beginnerProgram principalement à des fins d'apprentissage.

beginnerProgram n'est pas capable de gérer des abonnements ou des commandes en cours d'exécution.

Il est uniquement capable de gérer les entrées utilisateur des événements DOM.

Il ne nécessite qu'une view de rendre le model et une update à update fonction pour gérer les changements d'état.

Exemple

Considérons cet exemple minimal de beginnerProgram .

Le model dans cet exemple consiste en une seule valeur Int .

La fonction de update n'a qu'une seule branche, qui incrémente l' Int , stockée dans le model .

La view le modèle et attache un clic sur l’événement DOM.

Voir comment construire l'exemple dans Initialize et build

import Html exposing (Html, button, text)
import Html exposing (beginnerProgram)
import Html.Events exposing (onClick)


main : Program Never
main =
    beginnerProgram { model = 0, view = view, update = update }


-- UPDATE


type Msg
    = Increment

update : Msg -> Int -> Int
update msg model =
    case msg of
        Increment ->
            model + 1


-- VIEW


view : Int -> Html Msg
view model =
    button [ onClick Increment ] [ text ("Increment: " ++ (toString model)) ]

Programme

program est un bon choix, lorsque votre application ne nécessite aucune donnée externe pour l'initialisation.

Il est capable de gérer les abonnements et les commandes, ce qui offre beaucoup plus d'opportunités pour gérer les E / S, telles que la communication HTTP ou l'interopérabilité avec JavaScript.

L'état initial est requis pour renvoyer les commandes de démarrage avec le modèle.

L'initialisation du program nécessitera des subscriptions , ainsi que le model , la view et la update .

Voir la définition du type:

program :
    { init : ( model, Cmd msg )
    , update : msg -> model -> ( model, Cmd msg )
    , subscriptions : model -> Sub msg
    , view : model -> Html msg
    }
    -> Program Never

Exemple

Le moyen le plus simple d'illustrer comment vous pouvez utiliser les abonnements consiste à configurer une simple communication de port avec JavaScript.

Voir comment créer l'exemple dans Initialize and build / Embedding dans HTML

port module Main exposing (..)

import Html exposing (Html, text)
import Html exposing (program)


main : Program Never
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


port input : (Int -> msg) -> Sub msg


-- MODEL


type alias Model =
    Int


init : ( Model, Cmd msg )
init =
    ( 0, Cmd.none )


-- UPDATE


type Msg = Incoming Int


update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
    case msg of
        Incoming x ->
          ( x, Cmd.none )


-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    input Incoming


-- VIEW


view : Model -> Html msg
view model =
    text (toString model)
<!DOCTYPE html>
<html>
    <head>
        <script src='elm.js'></script>
</head>
    <body>
    <div id='app'></div>
    <script>var app = Elm.Main.embed(document.getElementById('app'));</script>
    <button onclick='app.ports.input.send(1);'>send</button>
</body>
</html>

Programme avec des drapeaux

programWithFlags n'a qu'une seule différence avec le program .

Il peut accepter les données lors de l'initialisation à partir de JavaScript:

var root = document.body;
var user = { id: 1, name: "Bob" };
var app = Elm.Main.embed( root, user );

Les données transmises depuis JavaScript s'appellent Flags.

Dans cet exemple, nous transmettons un objet JavaScript à Elm avec des informations utilisateur, il est conseillé de spécifier un alias de type pour les indicateurs.

type alias Flags =
    { id: Int
    , name: String
    }

Les indicateurs sont transmis à la fonction init , produisant l'état initial:

init : Flags -> ( Model, Cmd Msg )
init flags =
    let
        { id, name } =
            flags
    in
        ( Model id name, Cmd.none )

Vous remarquerez peut-être la différence par rapport à la signature de type:

programWithFlags :
    { init : flags -> ( model, Cmd msg )          -- init now accepts flags
    , update : msg -> model -> ( model, Cmd msg )
    , subscriptions : model -> Sub msg
    , view : model -> Html msg
    }
    -> Program flags

Le code d'initialisation est presque identique, car seule la fonction d' init est différente.

main =
    programWithFlags
        { init = init
        , update = update
        , view = view
        , subscriptions = subscriptions
        }

Communication parent-enfant à sens unique

L'exemple montre la composition du composant et le message unidirectionnel passant du parent aux enfants.

0.18.0

La composition des composants repose sur le balisage des messages avec Html.App.map

0.18.0

En 0.18.0 HTML.App été réduit en HTML

La composition du composant repose sur le balisage des messages avec Html.map

Exemple

Voir comment construire l'exemple dans Initialiser et construire

module Main exposing (..)

import Html exposing (text, div, button, Html)
import Html.Events exposing (onClick)
import Html.App exposing (beginnerProgram)


main =
    beginnerProgram
        { view = view
        , model = init
        , update = update
        }

{- In v0.18.0 HTML.App was collapsed into HTML
   Use Html.map instead of Html.App.map
-}
view : Model -> Html Msg
view model =
    div []
        [ Html.App.map FirstCounterMsg (counterView model.firstCounter)
        , Html.App.map SecondCounterMsg (counterView model.secondCounter)
        , button [ onClick ResetAll ] [ text "Reset counters" ]
        ]


type alias Model =
    { firstCounter : CounterModel
    , secondCounter : CounterModel
    }


init : Model
init =
    { firstCounter = 0
    , secondCounter = 0
    }


type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll


update : Msg -> Model -> Model
update msg model =
    case msg of
        FirstCounterMsg childMsg ->
            { model | firstCounter = counterUpdate childMsg model.firstCounter }

        SecondCounterMsg childMsg ->
            { model | secondCounter = counterUpdate childMsg model.secondCounter }

        ResetAll ->
            { model
                | firstCounter = counterUpdate Reset model.firstCounter
                , secondCounter = counterUpdate Reset model.secondCounter
            }


type alias CounterModel =
    Int


counterView : CounterModel -> Html CounterMsg
counterView model =
    div []
        [ button [ onClick Decrement ] [ text "-" ]
        , text (toString model)
        , button [ onClick Increment ] [ text "+" ]
        ]


type CounterMsg
    = Increment
    | Decrement
    | Reset


counterUpdate : CounterMsg -> CounterModel -> CounterModel
counterUpdate msg model =
    case msg of
        Increment ->
            model + 1

        Decrement ->
            model - 1

        Reset ->
            0

Balisage de message avec Html.App.map

Les composants définissent leurs propres messages, envoyés après les événements DOM émis, par exemple. CounterMsg de la communication parent-enfant

type CounterMsg
    = Increment
    | Decrement
    | Reset

La vue de ce composant enverra des messages de type CounterMsg , par conséquent la signature de type de vue est Html CounterMsg .

Pour pouvoir réutiliser counterView dans la vue du composant parent, nous devons transmettre chaque message CounterMsg via Msg du parent.

Cette technique s'appelle le marquage de message .

Le composant parent doit définir des messages pour la transmission des messages enfants:

type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll

FirstCounterMsg Increment est un message balisé.

0.18.0

Pour obtenir un counterView pour envoyer des messages marqués, nous devons utiliser la fonction Html.App.map :

Html.map FirstCounterMsg (counterView model.firstCounter)
0.18.0

Le package HTML.App été réduit dans le package HTML en v0.18.0

Pour qu'un counterView envoie des messages marqués, nous devons utiliser la fonction Html.map :

Html.map FirstCounterMsg (counterView model.firstCounter)

Cela modifie le type signature Html CounterMsg -> Html Msg , il est donc possible d'utiliser le compteur dans la vue parent et de gérer les mises à jour d'état avec la fonction de mise à jour du parent.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow