首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >子窗体数量可变的消化函数器(Snap/Heist)

子窗体数量可变的消化函数器(Snap/Heist)
EN

Stack Overflow用户
提问于 2012-10-07 21:13:58
回答 2查看 678关注 0票数 10

我正在移植一个网站从PHP到Snap w/ Heist。我已经成功地将一些简单的表单移植到使用消化函数,但现在我必须做一些需要使用子表单的棘手的表单。

这个应用程序管理零售店的传单制作,因此需要完成的任务之一是添加广告大小并在打印的传单上定义其物理尺寸。尺寸将根据页面类型(可由传单所有者配置)和方向(只能由管理员控制)而有所不同。

这个表单保证至少有3个单元格,最有可能有9个单元格(如上图所示,来自PHP版本),但理论上可以有无限的数量。

下面是我到目前为止所获得的dimensions子窗体:

代码语言:javascript
复制
data AdDimensions = AdDimensions
    { sizeId :: Int64
    , layoutId :: Int64
    , dimensions :: Maybe String
    }

adDimensionsForm :: Monad m => AdDimensions -> Form Text m AdDimensions
adDimensionsForm d = AdDimensions
    <$> "size_id" .: stringRead "Must be a number" (Just $ sizeId d)
    <*> "layout_id" .: stringRead "Must be a number" (Just $ layoutId d)
    <*> "dimensions" .: opionalString (dimensions d)

表单定义感觉不太正确(也许我的想法完全错了?)。AdDimensions.dimensions应为Maybe String,因为在运行查询以获取新广告大小的大小_id/布局_id的所有可能组合的列表时,从数据库返回时,它将为null,但在创建编辑表单时将运行的类似查询中,它将不为null。字段本身是必需的(在数据库中,ad_dimensions.dimensions设置为not null )。

从这里开始,我不知道去哪里告诉父窗体它有一个子窗体列表,也不知道如何使用Heist呈现它们。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-24 04:10:57

使用listOf功能(最初提出/回答问题时该功能并不存在),这就是人们如何处理它。这需要2个表单,其中表示列表类型的表单是一个formlet:

代码语言:javascript
复制
data Thing = Thing { name: Text, properties: [(Text, Text)] }

thingForm :: Monad m => Maybe Thing -> Form Text m Thing
thingForm p = Thing
    <$> "name" .: text (name <$> p)
    <*> "properties" .: listOf propertyForm (properties <$> p)

propertyForm :: Monad m => Maybe (Text, Text) -> Form Text m (Text, Text)
propertyForm p = ( , )
    <$> "name" .: text (fst <$> p)
    <*> "value" .: text (snd <$> p)

简单表单

如果您有一个简单的项列表,digestive functors-heist为此定义了一些拼接,但是您可能会发现最终得到的是无效的标记,特别是当您的表单在一个表中时。

代码语言:javascript
复制
<label>Name <dfInputText ref="formname" /></label>

<fieldset>
    <legend>Properties</legend>

    <dfInputList ref="codes"><ul>
    <dfListItem><li itemAttrs><dfLabel ref="name">Name <dfInputText ref="name" /></dfLabel>
        <dfLabel ref="code">Value <dfInputText ref="value" required /></dfLabel>
        <input type="button" name="remove" value="Remove" /></li></dfListItem>
    </ul>

    <input type="button" name="add" value="Add another property" /></dfInputList>
</fieldset>

There JavaScript provided by digestiveFunctors to control adding and removing elements from the form that has a jQuery dependency。我最终编写了自己的拼接以避免jQuery依赖,这就是为什么我没有使用提供的addControlremoveControl拼接(按钮类型元素的属性)。

复杂形式

由于标签是动态的,OP中的表单不能使用由消化函数器-抢劫器提供的拼接(例如,它们来自数据库),因为我们希望它在一个复杂的表格布局中。这意味着我们必须执行两个额外的任务:

手动生成标记

如果您还没有看过由digestive functors-heist拼接生成的标记,那么您可能想先看一下,这样您就可以确切地了解必须生成什么,以便能够正确地处理表单。

对于动态表单(例如,允许用户动态添加或删除新项目的表单),您将需要一个隐藏的索引字段:

代码语言:javascript
复制
<input type='hidden' name='formname.fieldname.indices' value='0,1,2,3' />

当您通过runForm

  • fieldname运行表单时,
  • formname =无论您如何命名表单=主表单中列表字段的名称(如果您正在使用子表单,请根据需要进行调整),在此示例中,它将命名为"properties"
  • value =逗号分隔的数字列表,该列表表示在提交表单时应处理的子表单的索引

删除列表中的一个项目或添加新项目时,需要调整此列表,否则新项目将被完全忽略,删除的项目仍将存在于您的列表中。对于像OP中那样的静态表单,这一步是不必要的。

如果您已经知道如何编写拼接,那么生成表单的其余部分应该非常简单。根据需要将数据分块(groupBy、chunksOf等)然后把它通过你的接头发送出去。

如果您还不能通过查看digestive splices-heist生成的标记来判断,则需要插入子窗体的索引值作为每个子窗体的字段的一部分。子窗体列表的第一个字段的输出HTML应如下所示:

代码语言:javascript
复制
<input type='text' name='formname.properties.0.name' value='Foo' />
<input type='text' name='formname.properties.0.value' value='Bar' />

(提示:将列表与从0开始的无限列表一起压缩)

在处理错误时将数据从表单中拉回

(如果这些代码实际上都不能像编写的那样编译,我提前道歉,但希望它说明了这个过程)

这一部分不像其他部分那么直接,你必须深入研究消化函数器的内部。基本上,我们将使用相同的函数来获取数据,并用它填充我们的东西。我们需要的函数是listSubViews

代码语言:javascript
复制
-- where `v` is the view returned by `runForm`
-- the return type will be `[View v]`, in our example `v` will be `Text`
viewList = listSubViews "properties" v

对于静态表单,只需将此列表与数据列表压缩在一起即可。

代码语言:javascript
复制
let x = zipWith (curry updatePropertyData) xs viewList

然后,您的updatePropertyData函数将需要通过使用fileInputRead函数将信息拉出视图来更新您的记录:

代码语言:javascript
复制
updatePropertyData :: (Text, Text) -> View Text -> (Text, Text)
updatePropertyData x v =
    let
        -- pull the field information we want out of the subview
        -- this is a `Maybe Text
        val = fieldInputRead "value" v
    in
        -- update the tuple
        maybe x ((fst x, )) val
票数 2
EN

Stack Overflow用户

发布于 2012-10-08 22:00:46

我很久以前就为消化函数器-0.2编写了a special combinator for this。这是一个非常棒的full featured solution,它包含了允许动态添加和删除字段的javascript code。这段代码是基于Chris和我为formlets包所做的一个更早的实现,这个包最终被消化函数器所取代。这个函数从来没有移植到与消化函数器在0.3中获得的新API一起工作。

这个问题很棘手,有一些微妙的情况,所以我建议你花点时间看看代码。我认为Jasper可能会接受一个很好的代码移植到当前版本的摘要函数中。只是还没有人做过这项工作。

编辑:现在已经为最新的消化函数器做了这件事。请参见listOf函数。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12769153

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档