Ограбление: Как вставить динамический список суб-шаблонов в шаблон?
Я пишу сайт для онлайн-опросов. У меня есть список вопросов, которые все идут на одной странице HTML, и список имеет неизвестную длину. Каждый вопрос имеет форму, хранящуюся в шаблоне qu1.tpl
и страница qu.tpl
, Теперь я хочу:
заменить некоторые имена в
qu1.tpl
за каждый вопросзаменить некоторые вещи в
qu.tpl
один рази придерживаться всех экземпляров
qu1.tpl
вqu.tpl
Используя то, что я узнал из учебника, я попытался рекурсивно заменить тег <qulist/>
с <apply template="qu1.tpl"><qulist/>
в qu.tpl
с помощью localHeist
а также bindString
но это не может работать, потому что qu.tpl
уже отображается, поэтому вновь вставленный тег применения не разрешается.
что я должен сделать вместо этого?
(Я думаю, это более общий вопрос. Если вы можете вспомнить другие приложения, к которым относится ответ, добавьте текст и теги для поисковых систем.)
3 ответа
В 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.
Спасибо Mightybyte за помощь мне с этим на IRC. после 8 часов, когда мне было запрещено отвечать на вопросы, вот мой вариант ответа:
создать сплайс, который читает шаблон qu1.tpl, создает его экземпляр (то есть, заполняет имя и номер вопроса в списке) и возвращает его. в этом вам поможет функция ограбления callTemplate. (этот сплайс называется сплайсексом в псевдокоде ниже.)
напишите другой сплайс, который сворачивает сплайсекс так, чтобы вы получили список (созданных) вопросов вместо одного. (функция сплайсинга в псевдокоде.)
используйте bindSplice вместо bindString.
псевдокод (протестирован, затем модифицирован и вырван из контекста) -
... -> 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 слишком слаб, чтобы создавать новые теги. Кто-нибудь хочет пометить это с "ограблением"?
ссылки по теме:
#snapframework канал в сети IRC freenode.
Когда я попытался выяснить циклы шаблонов, я несколько раз сталкивался с этим вопросом. К сожалению, все здесь, вероятно, устарело, версия 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 для запуска демонстрации.