Open aloco opened 1 month ago
I think you're after the templateHtml
option.
{
formieForm(handle: "simpleForm") {
templateHtml(options:"{\"renderJs\": true}")
}
}
One thing you'll want to do is set a Form Template and have it set CSS and JS inline, rather than output in the usual spot of the header and footer respectively. With that enabled, you'll get a bundle of everything you need to embed a Formie form on your BYO front-end.
Nice this is exactly what I need. Thanks!
Loading the form works so far but I still have two issues:
1) it looks like the phone field is broken when embedding the form in this way, other js depended fields work (e.g. the signature field)
2) in the markup, the action base url correctly points to my cms url, but when submitting the form via ajax it gets sent to the frontend url - any idea on this?
thank you!
I'm not sure how you're embedding your HTML, but I have just realised that using something like innerHTML
isn't going to work for <script>
elements. They can't be evaluated with innerHTML
and need to be appended to the DOM separately.
const formHandle = 'sample';
const endpoint = 'https://formie-craft5.test/api';
const query = `
{
formieForm(handle: "${formHandle}") {
templateHtml
}
}
`;
fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: query
})
})
.then(response => response.json())
.then(response => {
const $form = document.querySelector('#my-form');
$form.innerHTML = response.data.formieForm.templateHtml;
// Script tags won't work using `innerHTML`, they need to be evaluated differently
const scripts = $form.querySelectorAll('script');
scripts.forEach(script => {
const newScript = document.createElement('script');
newScript.type = 'text/javascript';
if (script.src) {
newScript.src = script.src; // Handle external scripts
} else {
newScript.textContent = script.textContent; // Handle inline scripts
}
document.body.appendChild(newScript);
});
});
Otherwise no JS is going to work correctly. But if your signature field is working correctly, I'd say that you already have something handling this, but I was getting similar issues when submitting the form via Ajax, it was just refreshing the page.
Just wanted to clarify you're handling that first?
In light of this, just added templateJs
and templateCss
for separate handling. To get this early, run composer require verbb/formie:"dev-craft-5 as 3.0.8"
.
const formHandle = 'sample';
const endpoint = 'https://formie-craft5.test/api';
const query = `
{
formieForm(handle: "${formHandle}") {
templateHtml
templateCss
templateJs
}
}
`;
fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: query
})
})
.then(response => response.json())
.then(response => {
console.log(response)
const $form = document.querySelector('#my-form');
// Inject HTML
$form.innerHTML = response.data.formieForm.templateHtml;
// Inject CSS
const cssContainer = document.createElement('div');
cssContainer.innerHTML = response.data.formieForm.templateCss;
document.head.appendChild(cssContainer);
// Inject JS
const scriptContainer = document.createElement('div');
scriptContainer.innerHTML = response.data.formieForm.templateJs;
// Extract and run each script separately to ensure execution
const scripts = scriptContainer.querySelectorAll('script');
scripts.forEach(script => {
const newScript = document.createElement('script');
if (script.src) {
newScript.src = script.src; // External scripts
} else {
newScript.textContent = script.textContent; // Inline scripts
}
document.body.appendChild(newScript);
});
})
.catch(error => {
console.error('Error:', error); // Handle any errors
});
Hi, thank you for the input, I am using Astros <Fragment set:html={formTemplateHtml} />
I tried your approach and the problem is the same, I digged a little further and realized that formies ajaxSubmit
function does this.$form.getAttribute("action")
which is not set on the form html, it fallbacks to window.location.href
doing the XMLHttpRequest. Looks like the action attribute is missing when retrieving the html in this way
PS: The JS seems to work (at least partially) because the form gets a new CSRF Token via:
// Wait until Formie has been loaded and initialized
document.addEventListener('onFormieInit', (event: any) => {
// Fetch the Form Factory once it's been loaded
let Formie = event.detail.formie;
// Refresh the necessary bits that are statically cached (CSRF inputs, captchas, etc)
Formie.refreshForCache(event.detail.formId);
});
That's there if you want to override the action
attribute of the form, which in this case, that's probably something you want to do, setting that to either the Craft index.php (or any link to Craft) or to the formie/submissions/submit
endpoint.
But while that's easy to do in custom templates (which is what this was originally for), it's not so much for GraphQL. I can make that amendment.
Ok thank you, yes it would be great when the form action points to the cms host as default so its less prone to errors when creating new forms in the backend while using it with GraphQL.
I solved this for now by setting the action
manually, this works so far. However I ran into a CSRF issue, because the withCredentials
of the XMLHttpRequest
is per default false
and currently, there is no way to configure this in formie. It might happen that the frontend runs with another domain than the cms so I think it makes sense to make this configurable.
In that case, it probably makes sense to disable CSRF validation using the enableCsrfValidationForGuests
config setting. In this instance, everyone is technically going to be a guest with a detached front-end.
What are you trying to do?
Currently working on a headless Craft CMS project with astro in front accessing data via GraphQL and trying to find the easiest way to use Formie in this setup. Since mapping all Formie data from GraphQL to actual HTML seems very complicated for simple forms I am looking for an easy solution for most cases.
What's your proposed solution?
For convenience I would like to request the actual HTML directly via GraphQL, including required scripts and styles .. Hyper for instance is providing a HTML string via GraphQL as
link
which is very handy when no customization is needed (besides replacing some urls)Additional context
No response