繁体   English   中英

具有可变子窗体数量的消化函子(捕捉/抢劫)

[英]Digestive Functors with a variable number of subforms (Snap/Heist)

我正在将网站从PHP移植到Snap with Heist。 我已经将一些简单的表单成功地移植到了消化函子上,但是现在我不得不做一些棘手的表单,这些表单需要使用子表单。

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

表格在PHP版本中是什么样的

保证此表单至少具有3个单元格,最有可能具有9个单元格(如上图所示,从PHP版本开始),但理论上可以有无限数量。

到目前为止,这是我对Dimensions子窗体的了解:

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 ,因为在运行查询以获取新广告尺寸的size_id / layout_id的所有可能组合的列表时从数据库返回时,它将为null,但不为null从创建编辑表单时将运行的类似查询中获取。 该字段本身是必需的(在数据库中ad_dimensions.dimensions设置not null )。

从这里开始,我不知道该去哪里告诉父表单它有一个子表单列表或如何使用Heist渲染它们。

我很早以前为此了一个特殊的combinator,用于digesting-functors-0.2。 这是一个功能非常齐全的解决方案 ,其中包括允许动态添加和删除字段的javascript代码 该代码基于Chris和我为更早实现的Formlet软件包所做的实现,而消化功能最终取代了它。 从来没有将此功能移植到与消化功能在0.3中使用的新API一起使用。

这个问题很棘手,并且有一些微妙的极端情况,因此我建议您花一些时间看一下代码。 我认为Jasper可能会在当前版本的消化功能中接受大量代码。 只是还没有人完成这项工作。

编辑:现在已经为最新的消化功能器完成了。 请参阅listOf函数。

使用listOf功能(最初询问/回答问题时不存在),这就是解决该问题的方法。 这需要2个表单,其中代表您列表类型的表单是一个表单:

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)

简单表格

如果您有一个简单的项目列表,则digesting-functors-heist为此定义了一些拼接,但是您可能会发现最终会得到无效的标记,尤其是在表格位于表格中的情况下。

<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>

提供的JavaScript通过digestiveFunctors控制添加和删除从具有一个jQuery依赖性的形式的元素 我最终写了我自己的文章以避免jQuery依赖,这就是为什么我不使用提供的addControlremoveControl接头(按钮类型元素的属性)的原因。

复杂形式

由于标签是动态的(例如,它们来自数据库), 并且因为我们希望在复杂的表布局中使用标签,因此OP中的表格无法使用由摘要功能键提供的拼接。 这意味着我们必须执行另外两个任务:

手动生成标记

如果您没有查看由摘要式功能键拼接生成的标记,则可能要先执行该操作,以使您对生成的内容有所了解,以便正确处理表单。

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

<input type='hidden' name='formname.fieldname.indices' value='0,1,2,3' />
  • formname =通过runForm运行时为表单命名的runForm
  • fieldname =主表单中列表字段的名称(如果使用子表单,请根据需要进行调整),在此示例中,其名称为“ properties”
  • 值=逗号分隔的数字列表,代表提交表单时应处理的子表单的索引

当列表中的一项被删除或添加了新项时,将需要调整此列表,否则新项将被完全忽略,并且删除的项仍将存在于列表中。 对于静态形式(如OP中的形式)而言,此步骤是不必要的。


如果您已经知道如何编写接头,则生成表格的其余部分应该很简单。 适当地分块数据(groupBy,chunksOf等),然后通过接头发送。

如果您不能通过浏览digesting-splices-heist生成的标记来分辨,则需要插入子表单的索引值作为每个子表单的字段的一部分。 这是子表单列表的第一个字段的输出HTML外观:

<input type='text' name='formname.properties.0.name' value='Foo' />
<input type='text' name='formname.properties.0.value' value='Bar' />

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

处理错误时将数据拉出表单

(如果此代码实际上无法按照编写的方式进行编译,我事先表示歉意,但希望可以说明该过程)

这一部分不如其他部分简单明了,因此您必须深入了解消化功能的内在特性。 基本上,我们将使用digesting-functors-heist所做的相同功能来取回数据并用它填充Thing。 我们需要的功能是listSubViews

-- 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

对于静态表单,这可以像将列表和数据列表一起压缩一样简单。

let x = zipWith (curry updatePropertyData) xs viewList

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM