如何使用 Fetch API 访问 <button type="submit"> 和 php 的名称和值对?

How to access name and value pair of <button type="submit"> with php using Fetch API?

当使用提交类型的按钮提交表单时,我需要按钮的名称和值(不是输入类型 = 提交)。

我知道每个人总是问为什么,即使“为什么”不是问题答案的一部分所以我会回答为什么以节省时间。我想要一个表格来指导一个人选择登录、注册或提交电子邮件验证。因此,拥有我可以为其设置标签的按钮,每个按钮都有一个给定名称的唯一值可以解决这个需求,但是当 BUTTON 类型时,名称和值不包含在 POST 和输入数据的其余部分中= 使用提交。

鉴于本网站 HTML5 规范中显示的信息 https://www.htmlquick.com/reference/tags/button-submit.html 它似乎应该有效。但是如果不添加 javascript 以手动将键值对添加到 post 中,它似乎不起作用。

现在,我想问一下为什么?如果只能将输入添加到数据列表,那么为什么没有更改提交输入标签的选项?

*编辑 到目前为止,每个人都同意我所做的应该有效,所以让我们进入具体案例,看看我们是否能找到问题所在。

使用这种形式:

<form data-targetblock="accountBlock" class="fetchForm" action="<?=ADDRESS ?>/MAINhubs/accountBlockHub.php" method="post">
  <fieldset>
    <legend>Member Login</legend>
    <input type="hidden" name="formTarget1" value="test">
    <button type="submit" name="formTarget" value="login">Log In</button>
    <button type="submit" name="formTarget" value="register">Register</button>
    <button type="submit" name="formTarget" value="verify">Verify Your Email</button>
  </fieldset>
</form>

随此发送:

function addFetch(event, targetBlock, domain)
{
  event.preventDefault();
  const form = new FormData(event.target);
  const request = new Request(event.target.action,
  {
    method: event.target.method,
    body: form,
    mode: 'same-origin',
    credentials: 'same-origin'
  });

  fetch(request)
  .then(response => {
    if(response.ok)
    {
      return response.text();
    }
    else
    {
      document.getElementById(targetBlock).innerHTML = 'ERROR! ERROR! There has been an ERROR!'
    }
  })
  .then(function(text){document.getElementById(targetBlock).innerHTML = text;})
  .catch(error => console.log('There was an error:', error))
}

转到这个:

<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === "POST")
{
    var_dump($_POST);
}
?>

当我点击登录时得到这个:

formTarget1 = test

我猜这与 Fetch 中的这一行有关:

const form = new FormData(event.target);

回答函数如何调用的问题,这个JS是运行将函数添加到所有适用的形式:

function fetchFormCallback(mutations)
{
  mutations.forEach(function(mutation)
  {
    for (const thisForm of Array.from(document.getElementsByClassName('fetchForm')))
    {
      addFormListener(thisForm, thisForm.dataset.targetblock)
    }
  });
}

function generalCallback(mutations)
{
  mutations.forEach(function(mutation)
  {
    // Take alertBlocks and move them to bottom of ID outerFrame because of IOS bug
    if (newAlertBlock = document.getElementById('alertMessageBlock'))
    {
      if (newAlertBlock.dataset.relocated !== 'true')
      {
        var destinationBlock = document.getElementById('outerFrame');
        destinationBlock.appendChild(newAlertBlock);
        newAlertBlock.dataset.relocated = 'true';
      }
    }
    // Get getElementsByClassName closeButton
    for (var closeButton of Array.from(document.getElementsByClassName('closeButton')))
    {
      if (closeButton.dataset.closeButton !== 'true')
      {
        closeButton.dataset.closeButton = 'true';
        closeButton.addEventListener('click', function(){this.parentNode.parentNode.removeChild(this.parentNode);});
      }
    }
    // Potentially auto close based on a closeButton class of AUTO
  });
}

document.addEventListener("DOMContentLoaded", function()
{
  var config = {childList: true};
  for (const thisForm of Array.from(document.getElementsByClassName('fetchForm')))
  { // setup all fetchforms
    addFormListener(thisForm, thisForm.dataset.targetblock);
    var thisTargetBlock = document.getElementById(thisForm.dataset.targetblock);
    // if notset dataset.mutationobserver OR
    if (thisTargetBlock.dataset.mutationobserver !== 'true')
    {
      thisTargetBlock.dataset.mutationobserver = 'true';
      var observer = new MutationObserver(fetchFormCallback);
      observer.observe(thisTargetBlock, config);
    }
  }
  config = {childList: true, subtree: true};
  var generalObserver = new MutationObserver(generalCallback);
  generalObserver.observe(document, config);
});

function addFormListener(form, targetBlock)
{ // first check if element has attribute set for eventListeners
  if (form.dataset.submitlistener !== 'true')
  {
    form.dataset.submitlistener = 'true';
    form.addEventListener('submit', function()
    {
      addFetch(event, targetBlock);
    });
  }
}

编辑:

我们已经确认这里的问题是 FormData 出于某种原因不应该包含提交值。为什么一个值应该被排除只是因为它在用例中可能不是 present/needed 超出了我的范围。我确实有理由将其包含在内并在上面进行了记录。我开发了这种结构,使其尽可能普遍适用,而无需为特殊情况使用添加代码。

所以现在我不断演变的问题变成了:

如何;使用上述函数,我可以获取单击的提交按钮的值,并将该名称值对包含在 FormData 中,而不更改这些函数的基本结构,否则这些函数将完全按照我希望它们在其他情况下执行的操作。

这个讨论说明了这是可能的,但已经根据规范进行了重新设计,不再完全按照我想做的去做:

如果我无法在提交时访问按钮的名称和值,那么我还不如为表单中的所有 BUTTON 元素创建另一个事件监听器,在单击时添加隐藏输入及其值。 . 在我去做那件事之前,我已经可以看到像 event.preventDefault(); 这样的障碍了。 addFetch 函数中的行可能会阻止点击发生?我想这又回到了反复试验,除非有人有更好的想法。

在你的 PHP:

$_POST['formTarget'];

将具有提交按钮的值。登录、注册等

但是我不会为此使用表格,没有必要。如果您希望它们看起来像按钮,我会简单地使用链接并将它们设置为按钮样式。

编辑:根据您对 post 的添加。我提供了另一种方法来使用 data attributes.

来完成此操作

HTML:

<fieldset>
    <legend>Member Login</legend>
    <button id="loginButton" data-url="getForm.php" data-target-block="#showForm" data-form-type="login">Log In</button>
    <button id="registerButton" data-url="getForm.php" data-target-block="#showForm" data-form-type="register">Register</button>
    <button id="verifyButton" data-url="getForm.php" data-target-block="#showForm" data-form-type="verify">Verify Your Email</button>
</fieldset>
<div id="showForm"></div>
<script>
    document.querySelector("#loginButton").addEventListener("click", addFetch);
    document.querySelector("#registerButton").addEventListener("click", addFetch);
    document.querySelector("#verifyButton").addEventListener("click", addFetch);
    function addFetch() {
        const data = new FormData;
        const targetBlock = this.dataset.targetBlock;
        for(element in this.dataset) {
            data.append(element, this.dataset[element]);
        }        
        const request = new Request(this.dataset.url,
        {
            method: "POST",
            body: data,
            mode: 'same-origin',
            credentials: 'same-origin',
        });
        fetch(request).then(response => {
            if(response.ok) {
            return response.text();
            } else {
            document.querySelector(targetBlock).innerHTML = 'ERROR! ERROR! There has been an ERROR!'
            }
        }).then(function(text){document.querySelector(targetBlock).innerHTML = text;})
        .catch(error => console.log('There was an error:', error))
    }
</script>

PHP:

<?php
if ($_SERVER['REQUEST_METHOD'] === "POST") {
    switch($_POST['formType']) {
        case 'verify':
            echo "verify Form";
        break; 
        case 'register':
            echo "Register Form";
        break; 
        case 'login':
            echo "Login Form";
        break; 
        default:
            echo "Not valid";
        break;
    }
}