Как я могу передать параметры списка в формах IHP?

#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 😄 Спасибо, этот проект работает именно так, как я хотел.