Trying to implement inline-editing on a card using HTMX. User clicks on the edit button, and JS replaces the card with a <form> contained in an HTML <template>. The form element, on submission, needs to make an hx-post request but makes a traditional submit request instead.
Tried to replicate the issue in a new page, and got the hx-request to be sent, by replacing the form.submit() to form.requestSubmit(). However, the same does not work on the actual page. Tried replacing the “confirm” svg icon with an actual submit button, put it inside the <form> element, but still did not solve the issue.
Here’s the relevant code snippets:
<div class="profileCard" id="personalData">
<div>
<h1>Personal Details</h1>
<!-- edit button: -->
<svg class="editBtn pdEdit" width="64px" height="64px" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg" stroke="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0" />
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" />
<g id="SVGRepo_iconCarrier">
<path
d="M20.1498 7.93997L8.27978 19.81C7.21978 20.88 4.04977 21.3699 3.32977 20.6599C2.60977 19.9499 3.11978 16.78 4.17978 15.71L16.0498 3.84C16.5979 3.31801 17.3283 3.03097 18.0851 3.04019C18.842 3.04942 19.5652 3.35418 20.1004 3.88938C20.6356 4.42457 20.9403 5.14781 20.9496 5.90463C20.9588 6.66146 20.6718 7.39189 20.1498 7.93997V7.93997Z"
stroke="#9290C3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>
<div class="field-1" id="userInfo">
<div class="field-row">
<div>
<label for="fname">First Name:</label>
<span id="fname">{{user_data.firstname | default('-', true)}}</span>
</div>
<div>
<label for="lname">Last Name:</label>
<span id="lname">{{user_data.lastname | default('-', true)}}</span>
</div>
<div>
<label for="phone">Phone:</label>
<span id="phone">{{user_data.phone_number | default('-', true)}}</span>
</div>
</div>
<div class="field-row">
<div>
<label for="email">Email:</label>
<span id="email"> {{user_data.email | default('-', true)}} </span>
</div>
<div>
<label for="city">City:</label>
<span id="city">{{user_data.city | default('-', true)}}</span>
</div>
<div>
<label for="country">Country:</label>
<span id="country">{{user_data.country | default('-', true) }}</span>
</div>
</div>
</div>
</div>
</div>
<template> <!-- form for inline-editing personal details -->
<div class="editFormContainer">
<h1>Personal Details</h1>
<div class="btn-grp">
<!-- tick icon : -->
<button class="confirm">
<svg width="20px" height="20px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
fill="#000000" stroke="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0" />
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" />
<g id="SVGRepo_iconCarrier">
<title />
<g id="Complete">
<g id="tick">
<polyline fill="none" points="3.7 14.3 9.6 19 20.3 5" stroke="limegreen"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
</g>
</g>
</g>
</svg>
</button>
<!-- cross icon : -->
<svg class="cancel" width="20px" height="20px" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0" />
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" />
<g id="SVGRepo_iconCarrier">
<path d="M19 5L4.99998 19M5.00001 5L19 19" stroke="#FF6347" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>
</div>
<div class="field-1">
<form hx-post="/update_profile" hx-target="#userInfo" hx-trigger="submit"
id="editForm">
<div class="field-row">
<div>
<label for="fname">First Name:</label>
<input type="text" name="fname" id="fname"
value="{{user_data.firstname | default('-', true)}}">
</div>
<div>
<label for="lname">Last Name:</label>
<input type="text" name="lname" id="lname"
value="{{user_data.lastname | default('-', true)}}">
</div>
<div>
<label for="phone">Phone:</label>
<input type="tel" name="phone" id="phone"
value="{{user_data.phone_number | default('-', true)}}">
</div>
</div>
<div class="field-row">
<div>
<label for="email">Email:</label>
<input type="email" name="email" id="email"
value="{{user_data.email | default('-', true)}}">
</div>
<div>
<label for="city">City:</label>
<input type="text" name="city" id="city" value="{{user_data.city | default('-', true)}}">
</div>
<div>
<label for="country">Country:</label>
<input type="text" name="country" id="country"
value="{{user_data.country | default('-', true)}}">
</div>
</div>
<button type="submit">Sumbit</button>
</form>
</div>
</div>
</template>
<script>
//when DOM is loaded:
document.addEventListener('DOMContentLoaded', () => {
const editBtn = document.querySelector('.pdEdit');
const formTemplate = document.querySelector('template');
const cardContainer = document.querySelector('#personalData');
const ogCard = document.querySelector('#personalData > div');
let editFormContainer; //to be used AFTER the template is added to DOM
editBtn.addEventListener('click', () => {
ogCard.style.display = 'none';
if (editFormContainer == null) { //if form is NOT already added to DOM
cardContainer.appendChild(formTemplate.content.cloneNode(true)); //add the form to DOM
editFormContainer = cardContainer.querySelector('.editFormContainer'); //get the form
//apply event listeners to confirm and cancel buttons:
document.querySelector('.confirm').addEventListener('click', () => {
console.log('svg clicked');
let form = document.querySelector('form');
if(form){
console.log('form found');
form.requestSubmit();
}
else{
console.log('form not found');
}
});
editFormContainer.querySelector('.cancel').addEventListener('click', () => {
editFormContainer.style.display = 'none';
ogCard.style.display = 'block';
});
}
else {
ogCard.style.display = 'none';
editFormContainer.style.display = 'block';
}
});
});
</script>
3