Translate

martes, 24 de junio de 2025

Text Fields en Elm


Vamos a crear una aplicación sencilla que invierte el contenido de un campo de texto.


import Browser

import Html exposing (Html, Attribute, div, input, text)

import Html.Attributes exposing (..)

import Html.Events exposing (onInput)


-- MAIN

main =

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


-- MODEL

type alias Model =

  { content : String

  }


init : Model

init =

  { content = "" }


-- UPDATE

type Msg

  = Change String


update : Msg -> Model -> Model

update msg model =

  case msg of

    Change newContent ->

      { model | content = newContent }


-- VIEW

view : Model -> Html Msg

view model =

  div []

    [ input [ placeholder "Text to reverse", value model.content, onInput Change ] []

    , div [] [ text (String.reverse model.content) ]

    ]


Este código es una ligera variación del ejemplo anterior. Se configura un modelo. Se definen algunos mensajes. Se indica cómo actualizar. Se crea la vista. La diferencia radica simplemente en cómo se completó este esqueleto. 

Siempre empiezo por adivinar cuál debería ser mi modelo. Sabemos que debemos registrar lo que el usuario escribe en el campo de texto. Necesitamos esa información para saber cómo representar el texto invertido. Así que lo hacemos así:


type alias Model =

  { content : String

  }

Esta vez representamos el modelo como un registro. El registro almacena la entrada del usuario en el campo de contenido.

¿para qué molestarse en tener un registro si solo contiene una entrada? ¿No se podría usar la cadena directamente? ¡Claro! Pero empezar con un registro facilita la adición de más campos a medida que nuestra aplicación se vuelve más compleja. Cuando llegue el momento en que necesitemos dos entradas de texto, tendremos que hacer muchos más ajustes.

Ya tenemos nuestro modelo, así que normalmente procedemos a crear una función de vista:


view : Model -> Html Msg

view model =

  div []

    [ input [ placeholder "Text to reverse", value model.content, onInput Change ] []

    , div [] [ text (String.reverse model.content) ]

    ]


Creamos un <div> con dos hijos. El hijo interesante es el nodo <input>, que tiene tres atributos:

  • placeholder es el texto que se muestra cuando no hay contenido.
  • value es el contenido actual de este <input>.
  • onInput envía mensajes cuando el usuario escribe en este nodo <input>.

Al escribir "bard", se generarían cuatro mensajes:

  1. Change "b"
  2. Change "ba"
  3. Change "bar"
  4. Change "bard"

Estos se incorporarían a nuestra función de actualización.

Solo hay un tipo de mensaje en este programa, por lo que nuestra actualización solo tiene que manejar un caso:


type Msg

  = Change String


update : Msg -> Model -> Model

update msg model =

  case msg of

    Change newContent ->

      { model | content = newContent }


Cuando recibimos un mensaje indicando que el nodo <input> ha cambiado, actualizamos el contenido de nuestro modelo. Por lo tanto, si escribiera "bard", los mensajes resultantes generarían los siguientes modelos:


  1. { content = "b" }
  2. { content = "ba" }
  3. { content = "bar" }
  4. { content = "bard" }

Necesitamos registrar esta información explícitamente en nuestro modelo; de lo contrario, no habría forma de mostrar el texto invertido en nuestra función de vista.