I have dashboard
endpoint where the user can view,edit,delete a campaign/form.
<button hx-get="{{ url_for('campaign_action' , campaign_id=campaign.id , username=username) }}"
hx-trigger="click" hx-target="#campaignContainer" hx-swap="innerHTML"
data-bs-toggle="modal" data-bs-target="#viewCampaignModal"
class="btn btn-primary" type="button">View</button>
<button hx-patch="{{ url_for('campaign_action' , campaign_id=campaign.id , username=username) }}"
hx-trigger="click" hx-target="#campaignContainer" hx-swap="innerHTML"
data-bs-toggle="modal" data-bs-target="#viewCampaignModal"
class="btn btn-warning" type="button">Edit</button>
<button hx-delete="{{ url_for('campaign_action' , campaign_id=campaign.id , username=username) }}"
hx-target="#campaign-{{ campaign.id }}" hx-swap="outerHTML" hx-confirm="Are you sure you want to delete this campaign?"
class="btn btn-danger" type="button">Delete</button>
These buttons send get,patch,delete request accordingly, to campaign_action
endpoint where I handle the request.
Also these buttons swap the content inside #campaignContainer
and
Bootstrap modal class is toggled on #viewCampaignModal
.
<div class="modal fade" id="viewCampaignModal" tabindex="-1" aria-hidden="true" aria-labelledby="modal-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-title">Edit Campaign</h5>
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="campaignContainer">
</div>
</div>
</div>
</div>
campaign_action
endpoint return campaign_action.html
back in response to the htmx requests for view (which sends a get request) and edit (which sends patch request).
@app.route(
"/dashboard/<string:username>/campagin/<int:campaign_id>",
methods=["GET", "POST", "PATCH", "DELETE"],
)
def campaign_action(username, campaign_id: int):
populated_form = AddCampaign(obj=CampaignManager.get({"id": campaign_id}))
disabled = False
if request.method == "GET":
disabled = True
elif request.method == "PATCH":
disabled = False
elif request.method == "DELETE":
CampaignManager.delete_campaign(campaign_id)
return ""
elif request.method == "POST" and populated_form.validate_on_submit():
CampaignManager.update(populated_form.data, campaign_id)
return redirect(url_for("dashboard", username=session["username"]))
return render_template(
"dashboard/campaign_action.html",
form=populated_form,
disabled=disabled,
username=username,
campaign_id=campaign_id,
)
Now the problem am facing is,
Whenever the Flask-WTForm
validation fails the form is rendered on a blank page.
I know that all the conditions in campaign_action
fail hence the form is rendered separately on blank page but what I want is to show the errors on the modal itself.
After many attempts of prompting chatgpt This solution worked perfectly for me.
<form method="POST" action="{{ url_for('campaign_action' ,username=username , campaign_id=campaign_id) }}" id="#modalForm"
hx-post="{{ url_for('campaign_action' , username=username , campaign_id=campaign_id) }}"
hx-target="#campaignContainer"
hx-swap= "innerHTML"
>
The form post method sends a request to campaign_action
endpoint for validation of form.
If the form is not validated then,
the form is again rendered , post request made from htmx inserts this current form (along with the errors) again into the dashboard.html
modal.
Which updates the modal and shows all the validation errors.
If the form is validated after making the post request on submission then we return an empty string along with an hx redirect.
return ("",{"HX-Redirect": url_for("dashboard", username=session["username"])})
HX-Redirect is necessary.
Flask redirect(url_for('dashboard'))
does not work.
Using Flask redirect results in rendering the dashboard inside the modal!!!
Why is that? I am not sure myself.