Heist:如何将子模板的动态列表插入模板?

时间:2011-07-22 09:33:37

标签: web-applications haskell haskell-snap-framework heist

我正在为在线调查撰写网站。我有一个问题列表,所有问题都在一个html页面上进行,列表的长度未知。每个问题的表单都存储在模板qu1.tpl中,页面为qu.tpl。现在我想:

  1. 为每个问题替换qu1.tpl中的一些名称

  2. 替换qu.tpl一次

  3. 中的一些内容
  4. 并将qu1.tpl的所有实例都粘贴到qu.tpl

  5. 使用我在本教程中学到的内容,我尝试使用<qulist/><apply template="qu1.tpl"><qulist/>qu.tpl中使用localHeist递归替换标记bindString,但这不能工作,因为qu.tpl已经呈现,因此新插入的应用标记无法解析。

    我该怎么做呢?

    (我想这是一个更普遍的问题。如果你能想到答案适用的其他应用程序,请为搜索引擎添加文字和标签。)

3 个答案:

答案 0 :(得分:4)

在Heist中,当你做一些涉及动态数据计算的事情时,你通常会使用拼接。您的前两个点可以通过绑定拼接来处理。对于第三点,我将首先创建一个呈现特定问题模板的拼接功能。它看起来像这样:

questionSplice :: Monad m => Int -> Splice m
questionSplice n = do
  splices <- setupSplicesForThisQuestion
  mTemplate <- callTemplate (B.pack ("qu"++(show n))) splices
  return $ fromMaybe [] mTemplate

现在,您可以为调查问题列表创建拼接:

surveyQuestions :: Monad m => Splice m
surveyQuestions = do
  questions <- getSurveyQuestions
  mapSplices questionSplice questions

然后,您可以将此拼接绑定到特定标记,并在qu.tpl或任何其他模板中的任何位置使用它。

这里重要的部分是callTemplate函数。 Heist的功能是从TemplateMonad计算中渲染模板。我不认为它在教程中被讨论过多,因为它不是人们通常关注的用例,而且很容易在API文档中遗漏。

答案 1 :(得分:1)

感谢mightybyte帮助我解决这个问题。在我被禁止回答自己的8小时之后,这是我对同一答案的变体:

  1. 构建一个读取模板qu1.tpl的拼接,实例化它(即填写列表中问题的名称和编号),然后返回它。 heist函数callTemplate可以帮助你。 (这个拼接在下面的伪代码中称为splicex。)

  2. 编写另一个折叠splicex的拼接,以便获得(实例化的)问题列表而不是单个问题。 (伪代码中的函数拼接。)

  3. 使用bindSplice而不是bindString。

  4. 伪代码(测试然后修改并撕掉上下文) -

     ... -> let
              splice :: Monad m => Splice m
              splice = foldM (\ ts (s, i) ->
                                 liftM ((++) ts) $ splicex (quName, quNumber))
                             []
                             (zip questionName [0..])
    
              splicex :: Monad m => (String, Int) -> Splice m
              splicex (quName, quNumber) =
                  do
                    mt <- callTemplate "qu1"
                            [ ("question-name", Data.Text.pack quName)
                            , ("question-number", Data.Text.pack $ show quNumber)
                            ]
    
                    case mt of
                      Nothing -> error "splice rendering failed."
                      Just (t :: Template) -> return t
             in
               -- fill in the list of (instatiated) questions
               heistLocal (bindSplice "qulist" splice) $
               -- before that, instantiate the overall page
               instantiatePage $
               render "qu"
    
    不过,我的sourceforge头像太弱而无法创建新标签。有人想用“抢劫”标记这个吗?

    链接:

    http://snapframework.com/

    freenode IRC网络上的#snapframework频道。

    http://snapframework.com/docs/tutorials/heist

答案 2 :(得分:0)

当我试图找出模板循环时,我在这个问题上多次偶然发现。可悲的是,这里的所有内容都可能已过时,版本0.5(或更低版本),而版本0.6(我猜)引入了runChildrenWith。

使用runChildrenWith的一个简单示例是:

list_test_entries.tpl:

<listTestEntries>
  <dt><testEntry/></dt>
  <dd>This is part of the repeated template</dd>
</listTestEntries>

Site.hs:

listTestEntriesHandler :: Handler App App  ()
listTestEntriesHandler = do
    results <- getData 
    renderWithSplices "list_test_entries"
        ("listTestEntries" ## listTestEntriesSplice results)

getData :: Handler App App [String]
getData = return ["1", "2", "3"]

listTestEntriesSplice  :: [String] -> I.Splice AppHandler
listTestEntriesSplice = I.mapSplices (I.runChildrenWith . listTestEntrySplice)

listTestEntrySplice :: Monad m => String -> Splices (HeistT n m Template)
listTestEntrySplice dataEntry = do
  "testEntry" ## I.textSplice (T.pack $ "data: " ++ dataEntry)

有关正在运行的演示,请参阅https://github.com/michaxm/heist-template-loop-demo