我正在移植从PHP站点,以捕捉W /大盗。 我已经移植了一些简单的形式成功地利用消化函子,但现在我不得不这样做需要使用子窗体的棘手的。
此应用程序管理生产传单零售商店,所以需要做的是将广告的大小和确定在印刷传单它的物理尺寸的任务之一。 大小将取决于页的类型(由锭翼所有者可配置)和其定向(这只能由管理员来控制)而变化。
这种形式的保证有最少3个细胞,最有可能会具有9个细胞(如上述从PHP版本图),但是在理论上可以有无限数目。
这是我到目前为止已经得到了尺寸子窗体:
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的新广告尺寸的可能组合的列表回来,我们会很空,但它会不会空从将创建编辑表单时运行的类似查询。 该场本身是必需的( ad_dimensions.dimensions
设置为not null
在数据库中)。
从这里,我不知道去哪里,告诉父窗体,它有子窗体列表或我会如何使用海斯特使它们。
我写了这个特殊的组合子前一段时间消化道-函子-0.2。 这是一个非常完整的功能解决方案 ,其中包括JavaScript代码 ,允许动态添加和删除字段。 该代码是基于更早的实现克里斯和我做了formlets包,它的消化,最终函子所取代。 此功能是从来没有移植新的API,消化,仿函数在0.3开始工作。
问题是棘手的,有一些细微的角落情况下,所以我建议你花一些时间看代码。 我认为碧玉可能会接受代码的好口进入消化道,仿函数的当前版本。 只是,没有人在做的工作呢。
编辑:这已经现在完成了最新的消化,仿函数。 见listOf功能。
使用listOf
功能(这是不在身边时,这个问题最初问/回答),这是一个将如何去了解它。 这需要2种形式,其中代表你的列表的类型的形式是formlet:
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)
简单的形式
如果你有一个项目的简单列表,消化,仿函数斯特定义了一些这方面的接头,但你可能会发现你会拥有合法的标记,特别是如果你的形式是在表中。
<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>
存在由digestiveFunctors提供来控制添加和删除从具有一个jQuery依赖性的形式的元素的JavaScript 。 最后我写我自己,以免jQuery的依赖,这就是为什么我不使用所提供addControl
或removeControl
接头(属性按钮类型的元素)。
复杂的形式
在OP形式不能使用被消化,函子斯特提供的接头,因为标签是动态的(例如,他们来自数据库), 因为我们希望它在一个复杂的表格布局。 这意味着我们必须执行2项额外的任务:
手动生成标记
如果你没有看过由消化,仿函数斯特拼接生成的标记,你可能想,让你得到你有什么产生这样你的表格可以正确处理一个想法,这样做第一。
(例如,在允许用户添加或删除对飞新项目的形式)对于动态表单,您将需要一个隐藏的索引字段:
<input type='hidden' name='formname.fieldname.indices' value='0,1,2,3' />
- 表格名称=不管你,当你通过运行它命名为您的形式
runForm
- 字段名=列表字段的名称,在主窗体(根据需要调整,如果你使用的子窗体),在这个例子中,将被命名为“属性”
- 值的形式被提交时=逗号分隔表示应被处理的子表单的索引号码列表
当从列表中的一个项目被删除或新添加,这个名单将需要进行调整,否则新项目将被完全忽略和已删除项目仍然会在你的列表中存在。 这个步骤是不必要的静态形式像一个在OP。
生成表格的其余部分应该是很简单的,如果你已经知道怎么写拼接。 块备份数据的适当(GROUPBY,chunksOf等),并通过您的拼接发送。
如果您已经不能通过查看消化,接头斯特生成的标记告诉,你需要插入您的子窗体的索引值作为每个子窗体字段的一部分。 t这是输出HTML应该是什么样子我们的子窗体列表中的第一个字段:
<input type='text' name='formname.properties.0.name' value='Foo' />
<input type='text' name='formname.properties.0.value' value='Bar' />
(提示:从0开始的无限列表一起压缩您的列表)
在处理错误时的数据拉回到你的形式
(我提前道歉,如果没有这个代码实际上是可以编译为写的,但希望它说明了此过程)
这部分比其他部分更小直线前进,你必须通过消化,函子本的内脏掏。 基本上,我们将使用相同的功能,消化系统,仿函数斯特确实给取回数据并填充我们的事吧。 我们需要的功能是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