#haskell #ihp
#haskell #ihp
Вопрос:
Я пытаюсь сделать множественный выбор частью моей формы в IHP. В настоящее время пытаюсь решить эту проблему с помощью нескольких примерно таких флажков в представлении.
renderIngredientSelection :: Ingredient -> Html
renderIngredientSelection ingredient = [hsx|
<li>
<input name="ingredients" type="checkbox" value={(get #name ingredient)} />{get #name ingredient}
</li>
|]
Итак, инструмент браузера сетевого журнала сообщает, что он правильно отправляет запрос, подобный этому.
barcode=5555555555555amp;name=Pancakeamp;ingredients=milkamp;ingredients=egg
Но в контроллере param
функция будет перехватывать только первый ingredients
параметр.
Есть ли какой-либо способ перехватить все эти параметры в контроллере? Я вижу в сетевом журнале, что создан список кортежей, содержащий все параметры, включая оба ingredients
параметра. Как я могу получить к этому доступ и отобразить его в список, подобный ["milk", "egg"]
?
Ответ №1:
Вы можете использовать allParams
для доступа к полным параметрам запроса, которые вы видите в журналах.
Для запроса, подобного:
barcode=5555555555555amp;name=Pancakeamp;ingredients=milkamp;ingredients=egg
Мы можем использовать allParams
вот так:
action MyAction = do
let ingredients = allParams
-- ingredients = [("barcode",Just "5555555555555"),("name",Just "Pancake"),("ingredients",Just "milk"),("ingredients",Just "egg")]
Нам все еще нужно отфильтровать этот список, чтобы возвращать только значения ингредиентов:
action MyAction = do
let ingredients = allParams
|> filter ((paramName, paramValue) -> paramName == "ingredients")
-- ingredients = [("ingredients",Just "milk"),("ingredients",Just "egg")]
Теперь нам нужно сопоставить эту карту ключ-значение-map только со значениями. Поскольку значение имеет значение maybe (например Just "milk"
), мы будем использовать mapMaybe
вместо map
. mapMaybe
выбрасывает все Nothing
значения и распаковывает Just
:
action MyAction = do
let ingredients = allParams
|> filter ((paramName, paramValue) -> paramName == "ingredients")
|> mapMaybe ((paramName, paramValue) -> paramValue)
-- ingredients = ["milk", "ingredients"]
У нас есть [ByteString]
сейчас. Большинство функций, с которыми мы имеем дело, ожидают Text
вместо ByteString
, поэтому давайте выполним преобразование с помощью cs
(cs — сокращение от convert string):
action MyAction = do
let ingredients :: [Text] = allParams
|> filter ((paramName, paramValue) -> paramName == "ingredients")
|> mapMaybe ((paramName, paramValue) -> paramValue)
|> map cs
-- ingredients = ["milk", "ingredients"]
Перемещая его в Application/Controller/Helper.hs
Для хорошей структуры кода я бы перенес эту функцию в Application/Controller/Helper.hs
вот так:
module Application.Helper.Controller
( ...
, paramList -- Don't forget the export :)
)
paramList name = allParams
|> filter ((paramName, paramValue) -> paramName == name)
|> mapMaybe ((paramName, paramValue) -> paramValue)
|> map cs
А затем использовать его в контроллере следующим образом:
action MyAction = do
let ingredients = paramList "ingredients"
Все функции в Application.Helper.Controller
автоматически доступны в наших контроллерах.
Комментарии:
1. Не могу поверить, что я не нашел функцию allParams в документах API 😄 Спасибо, этот проект работает именно так, как я хотел.