Modal
Introduction
IHP provides support to render Bootstrap 4 Modals out of the box. Here’s how the result can look like:
Layout Setup
Before we can build our modal, we have to make sure that your current application layout has modal rendering enabled.
Open your Web/View/Layout.hs
and add a {modal}
just before the closing </body>
tag:
defaultLayout :: Html -> Html
defaultLayout inner = [hsx|
<!DOCTYPE html>
<html lang="en">
<body>
{inner}
{modal}
</body>
</html>
|]
In case there is a {modal}
already you can skip this step. Don’t add the {modal}
twice.
Rendering Modal Views
Let’s say we have a ProjectsAction
displaying a list of projects. We have a NewProjectAction
that you can use to add projects.
data ProjectsController
= ProjectsAction
| NewProjectAction
Let’s turn the NewProjectAction
into a modal that renders on top of the projects list.
First we need to modify our NewProjectAction
. It currently looks like this:
action NewProjectAction = do
let project = newRecord
render NewView { .. }
We need to call setModal NewView { .. }
to turn the NewView
into a modal. We also need to call jumpToAction ProjectsAction
to render the NewView
on top of the ProjectsView
which is going to be rendered by the ProjectsAction
:
action NewProjectAction = do
let project = newRecord
setModal NewView { .. }
jumpToAction ProjectsAction
Let’s take a look at /NewPost
, it now looks like this:
The NewView
is now rendered inside the ProjectsView
(it’s rendered where the {modal}
is placed). Next, we’re going to add the modal styling.
Modal Styling
The Web/View/Projects/New.hs
view looks like this at the moment:
module Web.View.Projects.New where
import Web.View.Prelude
data NewView = NewView { project :: Project }
instance View NewView where
html NewView { .. } = [hsx|
<div class="container">
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href={ProjectsAction}>Projects</a></li>
<li class="breadcrumb-item active">New Project</li>
</ol>
</nav>
<h1>New Project</h1>
{renderForm project}
</div>
|]
We’re going to use renderModal
inside the html NewView { .. }
definition to turn this into a bootstrap-styled Modal view:
module Web.View.Projects.New where
import Web.View.Prelude
data NewView = NewView { project :: Project }
instance View NewView where
html NewView { .. } = renderModal Modal
{ modalTitle = "New Project"
, modalCloseUrl = pathTo ProjectsAction
, modalFooter = Nothing
, modalContent = [hsx|
{renderForm project}
|]
}
After that our /NewProject
view looks like this:
The call to renderModal Modal { .. }
returns the HTML code for the bootstrap modal. You can think of it as a template function where modalTitle
, modalCloseUrl
, etc. just fill in the placeholder variables for the modal.
Common Issues
Could not deduce (Controller ProjectsController) arising from a use of ‘jumpToAction’
This error comes up when you try to render a modal on top of another controllers action.
To fix this error you need to add an import statement to the file where jumpToAction
is called:
import Web.Controller.Projects () -- <----- ADD THIS LINE
instance Controller DeploymentsController where
action MyAction = do
jumpToAction ShowProjectAction { projectId }