Form not registering as active

I’m having trouble getting a form to register as being active on my hugo site. It has data-netlify="true" as an attribute and a title, but it doesn’t seem to get crawled. I’m using it as a call to action so the same form appears on a most of the site’s pages.

I’m using alpine.js to show the form and handle the submission. The form sits in a <template> tag when the page loads which might be an issue. However, I’ve also tried it in a standard <div> and it still wasn’t being crawled. You can see it here. The form is displayed after clicking the box with the speech bubble.

Hey @gsgs,

First port of call would be the forms debugging guide. Can you let me know if this helps?

Yes it definitely did help. Looks like each form needs a unique name. This isn’t a problem for me to do but it will create a bit of an admin headache. I have 2k+ pages on my Hugo site and technically the same form will be on most of them. Is there any way to avoid having 2k+ active forms listed in my Netlify admin?

Phwoar! Not what we want to be doing. That would be a nightmare, you’re right!

Could you make use of partials and place the form on this, then call it per-page? I’m pretty convinced that this would work!

@Scott the form was already set up as a partial in Hugo, but each page still ends up being static html. It’s very easy to give each form a unique id for the page but admin overload… Any other suggestions? Surely someone has run into this type of situation before.

Note: I’ve taken the form off the site for now. I don’t like the idea of losing submissions into the ether.

The partial should absolutely work. Just make sure you define the form only once.

It’s important to know that the form will need to be an HTML form! Can you show us the HTML form as finished when building (a link to the page etc)?

I’ll set up a single page with the form then post a link but in the mean time this is how I’ve implemented it:

single.html

        <div class="px-4 pb-12 md:pb-0">
            {{ with .Resources }} 
                {{partial "post-image.html" (dict "resources" . ) }}
            {{ end }}
        </div>
    </main>
    <aside class="md:w-2/5">
        <div class="mx-4 p-12 rounded-lg shadow-md ">
            <div class="{{ .CurrentSection.Params.inspo_id }}"><a class="text-xs uppercase tracking-widest inline-block py-2 px-6 rounded-lg mb-4" href="{{ .CurrentSection.Permalink }}">{{ .CurrentSection.Title }}</a></div>

            <h1 class="text-4xl font-bold leading-snug mb-6">
                <a href="{{$link}}">{{.Title}}</a>
            </h1>
            
            <a href="{{ $creditlink }}" class="inline-block p-4 mb-6 bg-gray-200 text-gray-500 uppercase hover:bg-gray-300 hover:text-gray-500 transition ease-in-out duration-200 rounded-lg">Credit: <i class="fab {{ $crediticon }}"></i> {{ $artist }}</a>

            <div class="flex flex-wrap">
                {{ range (.GetTerms "tags") }}
                        <a class="inline-block text-xs uppercase px-4 py-1 bg-greenblue-500 hover:bg-greenblue-400 text-white hover:text-white rounded-lg tracking-widest mr-2 mb-2 transition ease-in-out duration-200" href="{{ .Permalink }}">{{ .LinkTitle }}</a>
                {{ end }}
            </div>
        </div>

        {{partial "side-bar-form.html" (dict "section" .CurrentSection.Title "url" .Permalink ) }}
    </aside>
</article>

side-bar-form.html (partial)

<div class="relative" x-data="{showForm: false, loading: false, showAlertMessage: false, showSuccessMessage: false, name: '', email: '', message: '', errors: []}" x-cloak>

<div class="mt-6 mx-4 p-12 rounded-lg bg-gray-100 relative z-10">
    <div class="cursor-pointer" @click="showForm = ! showForm">
        <i class="far fa-comment-alt fa-3x fa-pull-left pt-2"></i>
        <p class="font-serif font-black text-2xl" > {{$form_heading}}</p>
        <p>Get in touch with us here! </p>
    </div>
</div>

<template x-if="showForm">
    <div class="-mt-2 mx-4 p-12 rounded-lg bg-white border-4 border-gray-100 origin-top relative z-0"  x-transition:enter="transition ease-out duration-300"
    x-transition:enter-start="opacity-0 transform scale-y-50"
    x-transition:enter-end="opacity-100 transform scaley-100"
    x-transition:leave="transition ease-in duration-300"
    x-transition:leave-start="opacity-100 transform scaley-100"
    x-transition:leave-end="opacity-0 transform scale-y-50">

        <div x-show="showSuccessMessage" 
            x-transition:enter="transition ease-out duration-300"
            x-transition:enter-start="opacity-0 transform scale-90"
            x-transition:enter-end="opacity-100 transform scale-100"
            x-transition:leave="transition ease-in duration-300"
            x-transition:leave-start="opacity-100 transform scale-100"
            x-transition:leave-end="opacity-0 transform scale-90">
            <div class="bg-green-400 border border-l-4 border-green-500 text-whte p-4 my-4 rounded-lg"
                role="success">
                <p>We will be in touch ASAP!</p>
            </div>
        </div>

        <form class="flex flex-col  w-full" name="work-contact" method="POST" action="/" data-netlify="true" x-on:submit.prevent="loading=true; 

        if (name == '') {
            errors = {
                name: ['The name field is required']
            }

            loading = false;
            showAlertMessage = true;
            return;
        }

        if (email == '') {
            errors = {
                email: ['The email field is required']
            }

            loading = false;
            showAlertMessage = true;
            return;
        }

        if (message == '') {
            errors = {
                message: ['The message field is required']
            }

            loading = false;
            showAlertMessage = true;
            return;
        }

        const expression = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
        const validEmail = expression.test(String(email).toLowerCase())

        if (email != '' && ! validEmail) {
            errors = {
                email: ['Please enter a valid email address']
            }

            loading = false;
            showAlertMessage = true;
            return;
        }
        let formData = { 'form-name': 'work-contact', 'name': name, 'email': email, 'message': message };
        fetch('/', {
            method: 'POST',
            headers: {
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
            },
            body: new URLSearchParams(formData).toString()
        })
        .then((result) => {
            console.log('Success:', result);
        })
        .then(data => {
            loading = false;
            showAlertMessage = false;
            showSuccessMessage = true;
            name = '';
            email = '';
            message = '';
            })
        .catch(err => console.error(err));
        ">
        <input type="hidden" name="work-type" value="{{.section}} enquiry">

        <label class="uppercase text-sm pb-2" for="name">Name</label>
        <input class="bg-white border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 rounded-lg relative" placeholder="Name*" name="name" type="text" x-model="name" x-on:keydown="delete errors['name']"
        x-bind:class="{ 'border-pink-500 text-pink-500': errors['name'] }">
        <template x-if="errors['name']">
            <span>
                <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                    style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 24 24">
                    <path
                        d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                </svg>
                <span class="text-pink-500 mb-4 text-sm block"
                    x-text="errors['name']"></span>
            </span>
        </template>

        <label class="uppercase text-sm pb-2" for="email">Email</label>
        <input class="bg-white  border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 rounded-lg relative" placeholder="Email*" name="email" type="text" x-model="email" x-on:keydown="delete errors['email']"
        x-bind:class="{ 'border-pink-500 text-pink-500': errors['email'] }">
        <template x-if="errors['email']">
            <span>
                <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                    style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 24 24">
                    <path
                        d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                </svg>
                <span class="text-pink-500 mb-4 text-sm block"
                    x-text="errors['email']"></span>
            </span>
        </template>

        <label class="uppercase text-sm pb-2" for="message">Project details</label>
        <textarea class="bg-white  border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 font-sans rounded-lg" placeholder="Tell us about your project" name="message" x-model="message" x-on:keydown="delete errors['message']"
        x-bind:class="{ 'border-pink-500 text-pink-500': errors['message'] }"></textarea>
        <template x-if="errors['message']">
            <span>
                <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                    style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 24 24">
                    <path
                        d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                </svg>
                <span class="text-pink-500 mb-4 text-sm block"
                    x-text="errors['message']"></span>
            </span>
        </template>

        <button class="p-4 bg-greenblue-500 text-white uppercase hover:bg-greenblue-400 hover:text-white transition ease-in-out duration-200 rounded-lg" type="submit" x-bind:disabled="loading == true">
            <template x-if="loading == false">
                <div>Get in touch <i class="fas fa-arrow-right fa-xs rotate45"></i></div>
            </template>
            <template x-if="loading == true">
                <div>Sending message...</div>
            </template>
        </button>
        </form>
    </div>
</template>

I’ve set up the form on a test page here: Test page

I also changed the action to: action="/" as it was previously set as a full url.

I’m working on a simple form trying to submit via AJAX, and I have it narrowed down to using Alpine.JS x-* attributes causing the form to not register/link.

My form without the x-data= and x-on:submit.prevent= attributes link to Netlify’s Forms as expected (although obviously AJAX doesn’t work then).

I also moved the JS for the submission event to a global object (as shown here), so my attribute looked like this: x-on:submit.prevent="submitForm"

Since both attributes are needed, I haven’t done further testing to determine which one is the culprit (although it may be both).

1 Like

@rthaut that’s a bit of a pain. I’m initiating a drop down with alpine so I’ll try using vanilla js for the form submission and validation. I’ll post an update if removing x-on:submit.prevent makes a difference.

1 Like

@rthaut looks like doing the submission using just js without alpine solved everything.

I’m not particularly good with js so just in case someone else is in the same boat that I was, here are a couple of reference links I used.

JS form tutorial
Helpful community forum post
Youtube vid specifically for netlify and js forms The video is linked in the community post but I missed it at first.

And if you just wanted to see my js and html here it is. I’m using tailwind if the classes look unfamiliar.

js

window.addEventListener("load", function () {
  // get the form
  const form = document.getElementById("work-contact");
  // get the success message
  const successMsg = document.getElementById("showSuccessMessage");

  // get all the form elements
  let userName = form.elements["name"];
  let userEmail = form.elements["email"];
  let userMessage = form.elements["message"];

  // set up required fields
  const requiredFields = [
    { input: userName, message: "Name is required" },
    { input: userEmail, message: "Email is required" },
    { input: userMessage, message: "Message is required" },
  ];

  function error(input, message) {
    // get error message template
    var et = input.previousElementSibling;
    // change class name so error message template shows
    et.classList.remove("h-0", "opacity-0");
    et.classList.add("h-100", "opacity-100");
    // get the span in the error template (et)
    const errorMsg = et.querySelector("span.errormsg");
    // add inner text into the span
    errorMsg.innerText = message;
    return false;
  }

  function success(input) {
    // get error message template
    var et = input.previousElementSibling;
    // change class name so error message template is hidden
    et.classList.remove("h-100", "opacity-100");
    et.classList.add("h-0", "opacity-0");
    // get the span in the error template (et)
    const errorMsg = et.querySelector("span.errormsg");
    // remove text message
    errorMsg.innerText = "";
    return true;
  }

  function requireValue(input, message) {
    // check if inputs are blank
    return input.value.trim() === "" ? error(input, message) : success(input);
  }

  function validateEmail(input) {
    // create regex to check if valid email pattern
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    // text regex against input value
    return re.test(input.value.trim())
      ? success(input)
      : error(input, "Invalid email format");
  }

  form.addEventListener("submit", (event) => {
    // prevent default form submit action
    event.preventDefault();

    // bool for async actions
    let valid = true;

    // create async function to perform actions in sequence
    async function validate() {
      // loop over required fields object and check if inputs are blank
      requiredFields.forEach((input) => {
        valid = requireValue(input.input, input.message);
      });
    }

    validate()
      .then(() => {
        if (valid) {
          // if no inputs are blank check if email field has a valid pattern
          valid = validateEmail(userEmail);
        }
      })
      .then(() => {
        if (valid) {
          // if no inputs are blank and email is valid
          //show success message
          successMsg.classList.remove("h-0", "opacity-0");
          successMsg.classList.add("h-auto", "opacity-100");
          // hide form
          form.classList.add("h-0", "opacity-0");
          // get formData
          const formData = new FormData(form);

          // post form data
          fetch(form.getAttribute("action"), {
            method: "POST",
            headers: {
              "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
            },
            body: new URLSearchParams(formData).toString(),
          }).then((res) => {
            if (res) {
              // reset form fields
              form.reset();
              console.log(res.ok);
            }
          });
        }
      });
  });
});

html

<form id="work-contact" class="flex flex-col w-full transition duration-200 ease-in-out" name="work-contact" data-netlify="true" action="/#contact-form">
            <input type="hidden" name="work-type" value="{{.section}} enquiry">
            
            <label class="uppercase text-sm pb-2" for="name">Name</label>
            <div class="h-0 transition duration-200 ease-in-out">
                <div class="border border-l-4 border-pink-500 px-4 py-2 mb-4 rounded-lg">  
                    <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                        style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                        viewBox="0 0 24 24">
                        <path
                            d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                    </svg>
                    <span class="errormsg text-pink-500 text-sm block"></span>
                </div>
            </div>
            <input class="bg-white border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 rounded-lg relative" placeholder="Name*" name="name" type="text">

            <label class="uppercase text-sm pb-2" for="email">Email</label>
            <div class="h-0 opacity-0 transition duration-200 ease-in-out">
                <div class="border border-l-4 border-pink-500 px-4 py-2 mb-4 rounded-lg">  
                    <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                        style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                        viewBox="0 0 24 24">
                        <path
                            d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                    </svg>
                    <span class="errormsg text-pink-500 text-sm block"></span>
                </div>
            </div>
            <input class="bg-white border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 rounded-lg relative" placeholder="Email*" name="email" type="text">

            <label class="uppercase text-sm pb-2" for="message">Project details</label>
            <div class="h-0 opacity-0 transition duration-200 ease-in-out">
                <div class="border border-l-4 border-pink-500 px-4 py-2 mb-4 rounded-lg">  
                    <svg class="w-6 h-6 text-pink-500 fill-current float-left mr-1"
                        style="top: 10px; right: 12px" xmlns="http://www.w3.org/2000/svg"
                        viewBox="0 0 24 24">
                        <path
                            d="M11.953,2C6.465,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.493,2,11.953,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z" />
                    </svg>
                    <span class="errormsg text-pink-500 text-sm block"></span>
                </div>
            </div>
            <textarea class="bg-white  border border-gray-400 focus:outline-none focus:border-greenblue-500 text-base px-4 py-3 mb-4 font-sans rounded-lg" placeholder="Tell us about your project" name="message"></textarea>
            
            <button class="p-4 bg-greenblue-500 text-white uppercase hover:bg-greenblue-400 hover:text-white transition ease-in-out duration-200 rounded-lg" type="submit" >
                Get in touch <i class="fas fa-arrow-right fa-xs rotate45"></i>
            </button>
        </form>
1 Like