Formulário de contacto AJAX
Os mesmos campos de contacto, enviados com fetch em JSON. O visitante fica na página e vê um estado curto.
O que está a copiar
Este modelo envia os mesmos campos de contacto com fetch, para o visitante ficar na sua página e ler um estado curto.
O formulário continua a ter uma ação e o método POST. Se o JavaScript não correr, o navegador faz um envio normal.
Essa reserva importa para navegadores mais antigos e para quem bloqueia scripts. Não mantém dois formulários.
O excerto principal envia JSON. Define Content-Type como application/json e Accept como application/json.
O sucesso é o booleano success no JSON. Quando é true, o excerto mostra a mensagem da resposta, ou um agradecimento curto, e limpa o formulário.
Quando é false, o excerto mostra a mensagem da resposta. O Formgong escreve essa mensagem no idioma de _lang.
JSON e FormData
Um corpo JSON tem de listar os campos que quer enviar. O excerto inclui access_key, _lang, name, email, phone, message e botcheck.
Se mais tarde retirar o comentário do Turnstile, o caminho JSON também copia cf-turnstile-response quando esse campo tem um valor.
O excerto extra usa FormData em vez de JSON. O navegador define o tipo de conteúdo, incluindo o boundary. Não defina Content-Type.
O FormData apanha cada campo do formulário, incluindo um token Turnstile se o widget estiver dentro do formulário.
Os dois caminhos enviam Accept: application/json. Sem esse cabeçalho, um envio normal do navegador recebe a página de agradecimento, não JSON.
Não envie ao mesmo tempo um corpo JSON e um corpo multipart. Escolha um. Os dois excertos são alternativas, não camadas.
Spam, Telegram e limites
Mantenha o honeypot com o nome botcheck, vazio, fora do ecrã, com tabindex -1. Um honeypot preenchido fica guardado como spam e não é entregue.
Os nomes dos campos ficam curtos para o Telegram os poder imprimir a negrito. Não mude email para uma frase longa.
A chave de acesso fica na página. Passá-la para um segredo de servidor não torna o formulário mais seguro, e este excerto não tem servidor.
No plano gratuito, o Telegram é imediato e o email é um resumo diário. A caixa de entrada conserva os envios durante 30 dias.
O plano gratuito inclui 300 envios por mês. Um envio de spam não gasta um desses.
Esta pré-visualização não envia. Ligue o excerto no seu site e depois envie um teste a partir dessa página.
O Formgong opera o serviço. Para ajuda com o produto, escreva para support@formgong.com.
Pré-visualização
Código do formulário
<form id="fg-ajax" action="https://formgong.com/submit" method="POST" style="position:relative">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="pt">
<label>Nome <input type="text" name="name" autocomplete="name" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" required></label>
<label>Telefone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Mensagem <textarea name="message" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Deixe este campo vazio <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<!--
Opcional. Ative o Turnstile neste formulário, retire estas marcas de comentário e cole a chave do sítio.
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY" data-language="pt"></div>
-->
<button type="submit">Enviar</button>
<p data-status role="status"></p>
</form>
<script>
(function () {
var form = document.getElementById("fg-ajax");
if (!form) return;
var status = form.querySelector("[data-status]");
form.addEventListener("submit", function (event) {
event.preventDefault();
var data = {
access_key: form.access_key.value,
_lang: form._lang.value,
name: form.name.value,
email: form.email.value,
phone: form.phone.value,
message: form.message.value,
botcheck: form.botcheck.value
};
var token = form.querySelector('[name="cf-turnstile-response"]');
if (token && token.value) data["cf-turnstile-response"] = token.value;
var body = JSON.stringify(data);
fetch("https://formgong.com/submit", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: body
}).then(function (res) { return res.json(); }).then(function (result) {
if (status) status.textContent = result && result.success ? (result.message || "Enviado. Obrigado!") : ((result && result.message) || "Não foi possível enviar. Tente novamente.");
if (result && result.success) form.reset();
}).catch(function () {
if (status) status.textContent = "Não foi possível enviar. Tente novamente.";
});
});
})();
</script>O mesmo formulário com FormData em vez de JSON
<form id="fg-ajax" action="https://formgong.com/submit" method="POST" style="position:relative">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="pt">
<label>Nome <input type="text" name="name" autocomplete="name" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" required></label>
<label>Telefone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Mensagem <textarea name="message" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Deixe este campo vazio <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<!--
Opcional. Ative o Turnstile neste formulário, retire estas marcas de comentário e cole a chave do sítio.
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY" data-language="pt"></div>
-->
<button type="submit">Enviar</button>
<p data-status role="status"></p>
</form>
<script>
(function () {
var form = document.getElementById("fg-ajax");
if (!form) return;
var status = form.querySelector("[data-status]");
form.addEventListener("submit", function (event) {
event.preventDefault();
var body = new FormData(form);
fetch("https://formgong.com/submit", {
method: "POST",
headers: { Accept: "application/json" },
body: body
}).then(function (res) { return res.json(); }).then(function (result) {
if (status) status.textContent = result && result.success ? (result.message || "Enviado. Obrigado!") : ((result && result.message) || "Não foi possível enviar. Tente novamente.");
if (result && result.success) form.reset();
}).catch(function () {
if (status) status.textContent = "Não foi possível enviar. Tente novamente.";
});
});
})();
</script>Perguntas e respostas
Porque é que o formulário ainda tem um URL de ação?
Para o envio continuar a funcionar quando o JavaScript está desligado. O script só chama preventDefault quando corre.
Devo enviar JSON ou FormData?
Qualquer um é válido. O JSON é explícito sobre cada campo. O FormData é mais curto quando acrescenta inputs mais tarde, porque lê o formulário.
A linha de estado fica vazia. O que falhou?
Verifique se Accept é application/json, se a chave de acesso corresponde a um formulário seu e se a página é servida por http ou https, não como ficheiro local.
Este formulário pode carregar um ficheiro?
Não neste modelo. Os campos de ficheiro precisam de anexos ligados e de um token Turnstile válido. Use a documentação do painel para essa configuração.