Formularios

Vamos a crear un pequeño formulario. Tiene un campo para tu nombre, otro para tu clave, y otro para verificar la clave. También vamos a hacer un poco de validación para asegurarnos de que ambas claves son iguales.

Abajo tienes el programa completo. Puedes abrirlo en el editor online. Trata de escribir algo mal para ver mensajes de error. Por ejemplo, cambia el nombre de un campo, como password, o de una función, como placeholder. ¡Apreta el botón azul!

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!" ]

Es bastante similar a nuestro ejemplo de campos de texto, pero con más campos.

Modelo

Yo siempre empiezo pensando en el Modelo. Sabemos que vamos a necesitar tres campos de texto, así que partamos con eso.

type alias Model =
    { name : String
    , password : String
    , passwordAgain : String
    }

Normalmente empiezo con un modelo mínimo, tal vez con un sólo campo. Después intento escribir las funciones view y update. En ese proceso suelo sentir la necesidad de guardar más cosas en Model. Si usamos esta estrategia de construir el modelo gradualmente, podemos tener un programa funcional en cada etapa de su desarrollo. No tendrá todas las funcionalidades desde un principio, pero llegaremos ahí de a poco.

Actualización

Hay veces en que tenemos una idea basante completa de cómo se vería el código de actualización. Sabemos que necesitamos cambiar los tres campos, así que necesitamos mensajes para cada caso.

type Msg
    = Name String
    | Password String
    | PasswordAgain String

Esto significa que update necesita una rama para cada variante:

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 rama usa la sintaxis de actualización de registros para transformar el campo correspondiente del modelo. Esto se parece a lo que hicimos en el ejemplo anterior, pero con más casos.

En view vamos a tener que hacer un poco más de trabajo.

Vista

Esta función view usa funciones de ayuda para organizar mejor la cosas:

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é aquí no?

Lo bueno del HTML en Elm es que input y div son sólo funciones comunes y corrientes. Reciben (1) una lista de atributos, y (2) una lista de nodos hijo. Ya que son sólo funciones, tenemos el poder completo de Elm para construir nuestras vistas. Podemos refactorizar código repetitivo y ponerlo en funciones de ayuda de nuestra propia creación. Y eso es justamente lo que estamos haciendo aquí.

La función view hace 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 si escribimos viewInput "text" "Name" "Bill" Name en Elm, se convertiría en un valor HTML como <input type="text" placeholder="Name" value="Bill"> cuando se despliegue en pantalla.

El cuarto hijo 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 claves. Si son iguales, retorna un texto en verde y un mensaje de afirmación. Si no son iguales, retorna un texto en rojo y un mensaje de ayuda.

Estas funciones de ayuda ya empiezan a mostrar el beneficio de que nuestra librería de HTML sea sólo código Elm. Podríamos haber puesto todo este código dentro de view, pero crear funciones de ayuda es completamente normal en Elm, incluyendo en el código de la vista. “Parece que está un poco difícil de entender. Probemos extrayéndolo a una función de ayuda”.

Ejercicios: Revisa este ejemplo en el editor online. Intenta añadir las siguientes funcionalidades a la función viewValidation:

  • Confirma que la clave es más larga que 8 caracteres.
  • Asegura que la clave tiene letras mayúsculas, minúsculas y dígitos numéricos.

Usa las funciones del módulo String para completar estos ejercicios.

Advertencia: Necesitamos aprender mucho más antes de poder enviar una solicitud HTTP. Sigue leyendo en orden hasta llegar a la sección sobre HTTP antes de intentarlo por tu cuenta. Te va a resultar mucho más fácil siguiendo esta guía.

Nota: Parece que los intentos de hacer librerías genéricas de validación no han dado muchos frutos. Creo que el problema es que los chequeos son más comúnmente resueltos con funciones normales. Éstas reciben argumentos y retornan un Bool o un Maybe. O sea, ¿para qué usar una librería para revisar que dos textos son iguales? De lo que hemos aprendido, el código más simple surge al escribir la lógica para tu caso particular, sin extras añadidos. Así que siempre intenta hacer esto antes de decidir que necesitas una solución más compleja.

results matching ""

    No results matching ""