Translate

martes, 1 de julio de 2025

Forms en Elm


Ahora crearemos un formulario básico. Tiene un campo para tu nombre, un campo para tu contraseña y un campo para verificarla. También realizaremos una validación muy sencilla para comprobar si las contraseñas coinciden.

A continuación, incluí el programa completo:


-- Input a user name and password. Make sure the password matches.

--

-- Read how it works:

--   https://guide.elm-lang.org/architecture/forms.html

--


import Browser

import Html exposing (..)

import Html.Attributes exposing (..)

import Html.Events exposing (onInput)


-- MAIN

main =

  Browser.sandbox { init = init, update = update, view = view }


-- MODEL

type alias Model =

  { name : String

  , password : String

  , passwordAgain : String

  }


init : Model

init =

  Model "" "" ""


-- UPDATE

type Msg

  = Name String

  | Password String

  | PasswordAgain String


update : Msg -> Model -> Model

update msg model =

  case msg of

    Name name ->

      { model | name = name }

    Password password ->

      { model | password = password }

    PasswordAgain password ->

      { model | passwordAgain = password }


-- VIEW

view : Model -> Html Msg

view model =

  div []

    [ viewInput "text" "Name" model.name Name

    , viewInput "password" "Password" model.password Password

    , viewInput "password" "Re-enter Password" model.passwordAgain PasswordAgain

    , viewValidation model

    ]


viewInput : String -> String -> String -> (String -> msg) -> Html msg

viewInput t p v toMsg =

  input [ type_ t, placeholder p, value v, onInput toMsg ] []


viewValidation : Model -> Html msg

viewValidation model =

  if model.password == model.passwordAgain then

    div [ style "color" "green" ] [ text "OK" ]

  else

    div [ style "color" "red" ] [ text "Passwords do not match!" ]



Esto es bastante similar a nuestro ejemplo de campo de texto, pero con más campos.

Siempre empiezo calculando el modelo. Sabemos que habrá tres campos de texto, así que sigamos con eso:


type alias Model =

  { name : String

  , password : String

  , passwordAgain : String

  }

Normalmente intento empezar con un modelo mínimo, quizás con un solo campo. Luego intento escribir las funciones de vista y actualización. Esto suele revelar que necesito añadir más elementos a mi modelo. Construir el modelo gradualmente de esta manera significa que puedo tener un programa funcional durante el proceso de desarrollo. Puede que aún no tenga todas las funciones, ¡pero casi las tiene!

A veces se tiene una idea bastante clara de cómo se verá el código básico de actualización. Sabemos que necesitamos poder cambiar nuestros tres campos, por lo que necesitamos mensajes para cada caso.


type Msg

  = Name String

  | Password String

  | PasswordAgain String


Esto significa que nuestra actualización necesita un caso para las tres variantes:


update : Msg -> Model -> Model

update msg model =

  case msg of

    Name name ->

      { model | name = name }

    Password password ->

      { model | password = password }

    PasswordAgain password ->

      { model | passwordAgain = password }


Cada caso utiliza la sintaxis de actualización de registros para garantizar que se transforme el campo correspondiente. Esto es similar al ejemplo anterior, pero con más casos.

Esta función de vista utiliza funciones auxiliares para hacer las cosas un poco más organizadas:


view : Model -> Html Msg

view model =

  div []

    [ viewInput "text" "Name" model.name Name

    , viewInput "password" "Password" model.password Password

    , viewInput "password" "Re-enter Password" model.passwordAgain PasswordAgain

    , viewValidation model

    ]


En ejemplos anteriores, usábamos input y div directamente. ¿Por qué dejamos de hacerlo?

Lo bueno de HTML en Elm es que input y div son funciones normales. Toman una lista de atributos y  una lista de nodos secundarios. Como usamos funciones normales de Elm, ¡tenemos todo el poder de Elm para ayudarnos a crear nuestras vistas! Podemos refactorizar código repetitivo y convertirlo en funciones auxiliares personalizadas. ¡Eso es exactamente lo que estamos haciendo aquí!


Así que nuestra función de vista tiene tres llamadas a viewInput:

viewInput : String -> String -> String -> (String -> msg) -> Html msg

viewInput t p v toMsg =

  input [ type_ t, placeholder p, value v, onInput toMsg ] []


Esto significa que escribir viewInput "text" "Name" "Bill" Name en Elm se convertiría en un valor HTML como <input type="text" placeholder="Name" value="Bill"> al mostrarse en pantalla.


La cuarta entrada es más interesante. Es una llamada a viewValidation:


viewValidation : Model -> Html msg

viewValidation model =

  if model.password == model.passwordAgain then

    div [ style "color" "green" ] [ text "OK" ]

  else

    div [ style "color" "red" ] [ text "Passwords do not match!" ]


Esta función primero compara las dos contraseñas. Si coinciden, se muestra texto verde y un mensaje positivo. Si no coinciden, se muestra texto rojo y un mensaje útil.

Estas funciones auxiliares empiezan a mostrar las ventajas de que nuestra biblioteca HTML sea código Elm normal. Podríamos incluir todo ese código en nuestra vista, pero crear funciones auxiliares es totalmente normal en Elm, incluso en el código de la vista.