| Copyright | (c) digitally induced GmbH 2020 |
|---|---|
| Safe Haskell | None |
| Language | GHC2021 |
IHP.View.Form.FormFor
Description
Synopsis
- formFor :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup
- formForWithOptions :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> (FormContext record -> FormContext record) -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup
- formForWithoutJavascript :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup
- formFor' :: (?context :: ControllerContext, ?request :: Request, HasField "meta" record MetaBag) => record -> Text -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup
- createFormContext :: (?request :: Request, HasField "meta" record MetaBag) => record -> FormContext record
- buildForm :: (?context :: ControllerContext) => FormContext model -> ((?context :: ControllerContext, ?formContext :: FormContext model) => Markup) -> Markup
- nestedFormFor :: forall (fieldName :: Symbol) childRecord parentRecord idType. (?context :: ControllerContext, ?formContext :: FormContext parentRecord, HasField fieldName parentRecord [childRecord], KnownSymbol fieldName, KnownSymbol (GetModelName childRecord), HasField "id" childRecord idType, InputValue idType, HasField "meta" childRecord MetaBag) => Proxy fieldName -> ((?context :: ControllerContext, ?formContext :: FormContext childRecord) => Markup) -> Markup
- submitButton :: (?formContext :: FormContext model, HasField "meta" model MetaBag, KnownSymbol (GetModelName model)) => SubmitButton
- class ModelFormAction record where
- modelFormAction :: record -> Text
Documentation
formFor :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup Source #
Forms usually begin with a formFor expression.
This is how a simple form can look like:
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{textField #title}
{textareaField #body}
{submitButton}
|]Calling this form from inside your HSX code will lead to the following HTML being generated:
<form method="POST" action="/CreatePost" id="" class="new-form">
<div class="form-group" id="form-group-post_title">
<label for="post_title">Title</label>
<input type="text" name="title" id="post_title" class="form-control" />
</div>
<div class="form-group" id="form-group-post_body">
<label for="post_body">Body</label>
<textarea name="body" id="post_body" class="form-control"></textarea>
</div>
<button class="btn btn-primary">Create Post</button>
</form>You can see that the form is submitted via POST. The form action has also been set by default to /CreatePost.
All inputs have auto-generated class names and ids for styling. Also, all name attributes are set as expected.
Field Values:
A form control is always filled with the value of the given field when rendering. For example, given a post
let post = Post { ..., title = "Hello World" }Rendering this, the input value will be set like:
>>>{textField #title}<input ... value="Hello World" />
Validation:
When rendering a record that has failed validation, the validation error message will be rendered automatically.
Given a post like this:
let post = Post { ..., title = "" }
|> validateField #title nonEmptyRendering {textField #title}, the input will have the css class is-invalid and an element with the error message will be rendered below the input:
<div class="form-group" id="form-group-post_title">
<label for="post_title">Title</label>
<input
type="text"
name="title"
placeholder=""
id="post_title"
class="form-control is-invalid "
/>
<div class="invalid-feedback">This field cannot be empty</div>
</div>formForWithOptions :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> (FormContext record -> FormContext record) -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup Source #
Like formFor but allows changing the underlying FormContext
This is how you can render a form with a id="post-form" id attribute and a custom data-post-id attribute:
renderForm :: Post -> Html
renderForm post = formForWithOptions formOptions post [hsx|
{textField #title}
{textareaField #body}
{submitButton}
|]
formOptions :: FormContext Post -> FormContext Post
formOptions formContext = formContext
|> set #formId "post-form"
|> set #customFormAttributes [("data-post-id", show formContext.model.id)]formForWithoutJavascript :: (?context :: ControllerContext, ?request :: Request, ModelFormAction record, HasField "meta" record MetaBag) => record -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup Source #
Like formFor but disables the IHP javascript helpers.
Use it like this:
renderForm :: Post -> Html
renderForm post = formForWithoutJavascript post [hsx|
{textField #title}
{textareaField #body}
{submitButton}
|]If you want to use this with e.g. a custom form action, remember that formForWithoutJavascript is just a shortcut for formForWithOptions:
renderForm :: Post -> Html
renderForm post = formForWithOptions formOptions post [hsx|
{textField #title}
{textareaField #body}
{submitButton}
|]
formOptions :: FormContext Post -> FormContext Post
formOptions formContext = formContext
|> set #formAction (pathTo BespokeNewPostAction)
|> set #disableJavascriptSubmission TrueformFor' :: (?context :: ControllerContext, ?request :: Request, HasField "meta" record MetaBag) => record -> Text -> ((?context :: ControllerContext, ?formContext :: FormContext record) => Markup) -> Markup Source #
Allows a custom form action (form submission url) to be set
The URL where the form is going to be submitted to is specified in HTML using the form's action attribute. When using formFor the action attribute is automatically set to the expected path.
E.g. given the below formFor code, the action is set to /CreatePost or /UpdatePost:
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{textField #title}
{textareaField #body}
{submitButton}
|]To override the auto-generated action attribute use the 'formFor'' function:
renderForm :: Post -> Html renderForm post = formFor' post "/my-custom-endpoint" [hsx||]
If you pass an action to that, you need to wrap it with pathTo:
renderForm :: Post -> Html renderForm post = formFor' post (pathTo CreateDraftAction) [hsx||]
createFormContext :: (?request :: Request, HasField "meta" record MetaBag) => record -> FormContext record Source #
Used by formFor to make a new form context
buildForm :: (?context :: ControllerContext) => FormContext model -> ((?context :: ControllerContext, ?formContext :: FormContext model) => Markup) -> Markup Source #
Used by formFor to render the form
nestedFormFor :: forall (fieldName :: Symbol) childRecord parentRecord idType. (?context :: ControllerContext, ?formContext :: FormContext parentRecord, HasField fieldName parentRecord [childRecord], KnownSymbol fieldName, KnownSymbol (GetModelName childRecord), HasField "id" childRecord idType, InputValue idType, HasField "meta" childRecord MetaBag) => Proxy fieldName -> ((?context :: ControllerContext, ?formContext :: FormContext childRecord) => Markup) -> Markup Source #
submitButton :: (?formContext :: FormContext model, HasField "meta" model MetaBag, KnownSymbol (GetModelName model)) => SubmitButton Source #
Renders a submit button
<button class="btn btn-primary">Create Post</button>
Example:
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{submitButton}
|]This will generate code like this:
<form method="POST" action="/CreatePost" id="" class="new-form">
<button class="btn btn-primary">Create Post</button>
</form>Custom Text
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{submitButton { label = "Create it!" } }
|]This will generate code like this:
<form method="POST" action="/CreatePost" id="" class="new-form">
<button class="btn btn-primary">Create it!</button>
</form>Custom Class
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{submitButton { buttonClass = "create-button" } }
|]This will generate code like this:
<form method="POST" action="/CreatePost" id="" class="new-form">
<button class="btn btn-primary create-button">Create Post</button>
</form>Disabled button
renderForm :: Post -> Html
renderForm post = formFor post [hsx|
{submitButton { buttonDisabled = True } }
|]This will generate code like this:
<form method="POST" action="/CreatePost" id="" class="new-form">
<button class="btn btn-primary create-button" disabled="disabled">Create Post</button>
</form>class ModelFormAction record where Source #
Returns the form's action attribute for a given record.
Methods
modelFormAction :: record -> Text Source #
Instances
| (HasField "id" record (Id' (GetTableName record)), HasField "meta" record MetaBag, KnownSymbol (GetModelName record), Show (Id' (GetTableName record))) => ModelFormAction record Source # | |
Defined in IHP.View.Form.FormFor Methods modelFormAction :: record -> Text Source # | |