具有可组合形式的动态形式
Dynamic form with composable-form
我正在尝试使用 hecrj/composable-form 在 Elm 0.19 中实现动态表单。
我收到一个 json,其中包含字段、它们的描述等,所以我事先不知道它会有多少字段。
所以定义表单的传统方式:
Form.succeed OutputValues
|> Form.append field1
|> Form.append field2
不起作用,因为我事先不知道 OutputValues
结构。
我看到有一个函数 Form.list
看起来像是一条很有前途的路径,尽管它似乎期望所有字段都相等,但我的情况并非如此,我可能有一个文本字段和一个 [=例如 27=] 字段。
这个库有没有直接的方法可以做到这一点?
谢谢。
表单库未明确支持您尝试执行的操作,但我们可以让它发挥作用!
tldr;
这是我的示例,说明如何使用 JSON 并创建表单:https://ellie-app.com/bJqNh29qnsva1
如何到达那里
Form.list
绝对是有前途的道路。您也完全正确,Form.list
要求所有字段都属于同一类型。让我们从这里开始吧!我们可以通过创建自定义类型来创建一个可以容纳它们的数据结构。在我的例子中,我称之为 DynamicFormFieldValue
。我们将为每种字段制作一个变体。我为文本、整数和 select 列表创建了一个。每个人都需要保存字段的值和所有附加项(如标题和默认值)以使其显示得很好。这将是我们将 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
根据值改变表单。因此,我们将在自定义类型和 return 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
在设计时并未考虑 use-case。我们希望列表保持相同的长度并且只是被迭代。为此,我们将删除“添加”和“删除”按钮,并强制提供一个虚拟默认值(永远不会被使用)。
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 示例演示了其余内容,您可以根据需要进行调整!
我正在尝试使用 hecrj/composable-form 在 Elm 0.19 中实现动态表单。
我收到一个 json,其中包含字段、它们的描述等,所以我事先不知道它会有多少字段。
所以定义表单的传统方式:
Form.succeed OutputValues
|> Form.append field1
|> Form.append field2
不起作用,因为我事先不知道 OutputValues
结构。
我看到有一个函数 Form.list
看起来像是一条很有前途的路径,尽管它似乎期望所有字段都相等,但我的情况并非如此,我可能有一个文本字段和一个 [=例如 27=] 字段。
这个库有没有直接的方法可以做到这一点? 谢谢。
表单库未明确支持您尝试执行的操作,但我们可以让它发挥作用!
tldr;
这是我的示例,说明如何使用 JSON 并创建表单:https://ellie-app.com/bJqNh29qnsva1
如何到达那里
Form.list
绝对是有前途的道路。您也完全正确,Form.list
要求所有字段都属于同一类型。让我们从这里开始吧!我们可以通过创建自定义类型来创建一个可以容纳它们的数据结构。在我的例子中,我称之为 DynamicFormFieldValue
。我们将为每种字段制作一个变体。我为文本、整数和 select 列表创建了一个。每个人都需要保存字段的值和所有附加项(如标题和默认值)以使其显示得很好。这将是我们将 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
根据值改变表单。因此,我们将在自定义类型和 return 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
在设计时并未考虑 use-case。我们希望列表保持相同的长度并且只是被迭代。为此,我们将删除“添加”和“删除”按钮,并强制提供一个虚拟默认值(永远不会被使用)。
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 示例演示了其余内容,您可以根据需要进行调整!