Как структурировать сообщения и обновлять функции с переменным количеством элементов пользовательского интерфейса в Elm? - PullRequest
0 голосов
/ 31 августа 2018

Привет StackOverflow!

Предположим, у меня есть приложение Elm с переменным количеством полей ввода текста. Я хотел бы отразить состояние этих полей ввода в модели.

Модель и вид достаточно просты: вид просто имеет где-то поле Array String.

Затем представление вычисляется просто путем вызова List.map (HTML input ...) в этом списке строк.

Однако я немного растерялся, как сделать функцию обновления и тип сообщения.

Сообщение может быть примерно таким:

type Msg = InputFieldUpdated Int String

Здесь Int относится к позиции в массиве, которую имеет обновляемая строка. Однако, если я делаю это таким образом, я могу создавать сообщения, которые ссылаются на несуществующие позиции массива, просто устанавливая для Int значение, выходящее за пределы допустимого диапазона.

Для фиксированного количества элементов ввода можно очень элегантно решить эту проблему, просто используя тип объединения с различным значением для каждого входа, но как насчет моей ситуации? В области «сделать невозможные состояния невозможными», есть ли какая-то хитрость для того, чего мне не хватает?

1 Ответ

0 голосов
/ 31 августа 2018

Однако, если я делаю это таким образом, я могу создавать сообщения, которые ссылаются на несуществующие позиции массива, просто устанавливая для Int значение, выходящее за пределы диапазона.

Согласно документации Array.set, массив остается неизменным, если индекс выходит за пределы диапазона.

Пожалуйста, посмотрите на этот пример приложения ellie . Это в основном моделирует проблему, которую вы описали. Отображается массив элементов, и элементы могут быть добавлены динамически:

view : Model -> Html Msg
view model =
    div []
        [ div [] (toList (Array.indexedMap viewElement model.elements))
        , button [ onClick Add ] [ text "Add" ]
        ]

Чтобы обновить определенный элемент, вам нужно получить его по индексу. Поскольку тип результата из Array.get равен Maybe a, система типов заставит вас обработать все случаи (когда элемент существует и не существует):

Increment index ->
    case get index model.elements of
        Just element ->
            { model | elements = set index (element + 1) model.elements }

        Nothing ->
            model

Пример приведен только для демонстрации: если вам не нужен текущий элемент, можно безопасно использовать функцию Array.set.

...