#elm
#elm
Вопрос:
Я пытаюсь реализовать динамическую форму в Elm 0.19, используя hecrj / composable-form.
Я получаю json с полями, их описаниями и т. Д., Поэтому я заранее не знаю, сколько в нем будет полей.
Итак, традиционный способ определения формы:
Form.succeed OutputValues
|> Form.append field1
|> Form.append field2
не работает, потому что я не знаю OutputValues
структуру заранее.
Я видел, что есть функция Form.list
, которая выглядит как многообещающий путь, хотя, похоже, она ожидает, что все поля равны, что не в моем случае, например, у меня может быть текстовое поле и поле выбора.
Есть ли какой-нибудь прямой способ сделать это с помощью этой библиотеки? Спасибо.
Ответ №1:
Библиотека форм явно не поддерживает то, что вы пытаетесь сделать, но мы можем заставить ее работать!
tldr;
Вот мой пример того, как вы можете использовать JSON и создать форму: https://ellie-app.com/bJqNh29qnsva1
Как туда добраться
Form.list
безусловно, многообещающий путь. Вы также совершенно правы, что Form.list
требует, чтобы все поля были одного типа. Итак, давайте начнем с этого! Мы можем создать одну структуру данных, которая может их содержать, создав пользовательский тип. В моем примере я вызвал это DynamicFormFieldValue
. Мы создадим вариант для каждого типа поля. Я создал их для текста, целых чисел и списка выбора. Каждая из них должна содержать значение поля и все дополнительные параметры (например, заголовок и значение по умолчанию), чтобы оно отображалось красиво. Это будет то, во что мы декодируем JSON, каково значение формы и каким будет вывод формы. Результирующие типы выглядят следующим образом:
type alias TextFieldRequirements =
{ name : String
, default : Maybe String
}
type alias IntFieldRequirements =
{ name : String
, default : Maybe Int
}
type alias SelectFieldRequirements =
{ name : String
, default : Maybe String
, options : List ( String, String )
}
type DynamicFormFieldValue
= TextField String TextFieldRequirements
| IntField Int IntFieldRequirements
| SelectField String SelectFieldRequirements
Чтобы отобразить форму, вам просто нужна функция, которая может принимать значение формы и отображать соответствующий виджет формы. Библиотека форм позволяет Form.meta
изменять форму на основе значения. Итак, мы сопоставим шаблон с пользовательским типом и вернем Form.textField
, Form.numberField
, или Form.selectField
. Что — то вроде этого:
dynamicFormField : Int -> Form DynamicFormFieldValue DynamicFormFieldValue
dynamicFormField fieldPosition =
Form.meta
(field ->
case field of
TextField textValue ({ name } as requirements) ->
Form.textField
{ parser = _ -> Ok field
, value = _ -> textValue
, update = value oldValue -> TextField value requirements
, error = always Nothing
, attributes =
{ label = name
, placeholder = ""
}
}
IntField intValue ({ name } as requirements) ->
Form.numberField
{ parser = _ -> Ok field
, value = _ -> String.fromInt intValue
, update = value oldValue -> IntField (Maybe.withDefault intValue (String.toInt value)) requirements
, error = always Nothing
, attributes =
{ label = name
, placeholder = ""
, step = Nothing
, min = Nothing
, max = Nothing
}
}
SelectField selectValue ({ name, options } as requirements) ->
Form.selectField
{ parser = _ -> Ok field
, value = _ -> selectValue
, update = value oldValue -> SelectField value requirements
, error = always Nothing
, attributes =
{ label = name
, placeholder = ""
, options = options
}
}
)
Подключение этой функции отображения к библиотеке немного неудобно. Form.list
не был разработан с учетом варианта использования. Мы хотим, чтобы список оставался той же длины и просто повторялся. Для достижения этой цели мы удалим кнопки «добавить» и «удалить» и будем вынуждены указать фиктивное значение по умолчанию (которое никогда не будет использовано).
dynamicForm : Form (List DynamicFormFieldValue) (List DynamicFormFieldValue)
dynamicForm =
Form.list
{ default =
-- This will never get used
TextField "" { name = "", default = Nothing }
, value = value -> value
, update = value oldValue -> value
, attributes =
{ label = "Dynamic Field Example"
, add = Nothing
, delete = Nothing
}
}
dynamicFormField
Надеюсь, пример ellie продемонстрирует остальное, и вы сможете адаптировать его к своим потребностям!
Комментарии:
1. Кроме того, если некоторые поля являются обязательными или нет, они также могут быть обработаны, как показано здесь: ellie-app.com/bMvRDyhLDF8a1