Как получить доступ к паре имени и значения ‹тип кнопки = отправить› с помощью php с помощью Fetch API?

Мне нужно имя и значение кнопки (не тип ввода = отправить), когда форма отправляется с помощью кнопки типа отправки.

Я знаю, что все всегда спрашивают, почему, хотя это не является частью ответа на вопрос, поэтому я отвечу, почему, чтобы сэкономить время. Я хочу, чтобы форма направляла человека на выбор: войти в систему, зарегистрироваться или отправить подтверждение по электронной почте. Таким образом, наличие кнопок, для которых я могу установить метку, каждая из которых имеет уникальное значение для данного имени, решит эту проблему, но имя и значения не включаются в POST с остальными входными данными, когда используется тип BUTTON = submit .

Учитывая информацию в спецификации HTML5, показанную на этом сайте https://www.htmlquick.com/reference/tags/button-submit.html похоже, что это должно работать. Но если не считать добавления javascript для ручного добавления пары ключ-значение в сообщение при нажатии, это, похоже, не работает.

Теперь я хочу спросить, почему? Если в список данных можно добавить только входные данные, то почему нет возможности изменить метку входных данных отправки?

* РЕДАКТИРОВАТЬ Пока что все согласны с тем, что то, что я сделал, должно работать, поэтому давайте перейдем к конкретному случаю и посмотрим, сможем ли мы найти, в чем проблема.

Используя эту форму:

<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 = тест

Я предполагаю, что это связано с этой строкой в ​​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 по какой-то причине не должен включать значение отправки. Почему значение должно быть исключено только потому, что оно может не присутствовать/не понадобиться в варианте использования, мне не понятно. У меня есть причина, по которой это должно быть включено, и я задокументировал это выше. Я разработал эту структуру так, чтобы она была как можно более универсальной без добавления кода для особых случаев.

Итак, теперь мой развивающийся вопрос стал таким:

Как; используя приведенные выше функции, я могу получить значение нажатой кнопки отправки и включить эту пару значений имени в FormData без изменения фундаментальной структуры этих функций, которые в противном случае делают именно то, что я хочу, чтобы они делали во всех остальных случаях.

Это обсуждение показывает, что это возможно, но было переработано на основе спецификации, чтобы больше не делать именно то, что я пытаюсь сделать: Объект FormData() не добавляет вводы типа submit из формы, в то время как в Firefox

Если я не могу получить доступ к имени и значению кнопки в момент отправки, то я мог бы также сделать еще один прослушиватель событий для всех элементов BUTTON в формах, который добавляет скрытый ввод с его значениями при нажатии... Прежде чем я пойду и сделать это, я уже вижу препятствия, такие как event.preventDefault(); строка в функции addFetch может предотвратить нажатие кнопки? Я думаю, что это снова метод проб и ошибок, если у кого-то нет лучшей мысли.


person FolioGraphic    schedule 30.11.2020    source источник
comment
Я не уверен, что понимаю вашу проблему? Вы пробовали $_POST['formTarget']? Не могли бы вы также показать нам соответствующий PHP-код?   -  person Magnus Eriksson    schedule 30.11.2020
comment
Может быть, тогда нам следует спросить о вашей среде. Если имя и значение нажатой кнопки не отображаются в $_POST, существуют другие проблемы.   -  person RiggsFolly    schedule 30.11.2020
comment
Да, это то, что я подозреваю, но не могу понять, что может быть не так. Я пришел к этому методу из-за других факторов, которые могут иметь значение, эта форма отправляется, как вы могли подозревать, используя API выборки для вставки возвращенной страницы в определенную часть открытой страницы.   -  person FolioGraphic    schedule 30.11.2020
comment
Обновлен вопрос с указанием особенностей, которые могут быть причиной проблемы.   -  person FolioGraphic    schedule 30.11.2020
comment
Можете ли вы предоставить, как вы вызываете эту функцию? Также FormData не включает значение кнопки отправки.   -  person mikeroq    schedule 30.11.2020
comment
Добавлен способ вызова этой функции. Но, похоже, вы уже знаете, что проблема в FormData. Как мне добавить значения кнопки отправки в FormData с учетом показанного кода? Я предполагаю, что я могу что-то сделать, чтобы добавить имя и значение нажатой кнопки в FormData в точке этой строки?   -  person FolioGraphic    schedule 30.11.2020
comment
Я обновил свой ответ, чтобы дать вам альтернативу. Просто быстро и грязно не хотелось пытаться все переписать.   -  person mikeroq    schedule 30.11.2020


Ответы (1)


В вашем PHP:

$_POST['formTarget'];

Будет иметь значение кнопки отправки. Либо войти, зарегистрироваться и т.

Однако я бы не стал использовать форму для этого, в этом нет необходимости. Я бы просто использовал ссылки и стилизовал их как кнопки, если бы вы хотели, чтобы они выглядели как кнопки.

Изменить: на основе ваших дополнений к сообщению. Я предлагаю альтернативный способ сделать это, используя атрибуты данных.

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;
    }
}
person mikeroq    schedule 30.11.2020
comment
Спасибо за ответ, это именно то, что я хотел бы сказать на этот вопрос, но $_POST['formTarget'] не существует, когда я отправляю эту форму. я проверил, добавив скрытый ввод со значением имени и выполнил цикл foreach, чтобы повторить все в $_POST, и только скрытый ввод будет отображаться. Я ценю рекомендацию, но я пришел к этому методу из-за других факторов, которые могут иметь значение, эта форма отправляется, как вы могли подозревать, с использованием API-интерфейса выборки для вставки возвращенной страницы в определенную часть открытой страницы. - person FolioGraphic; 30.11.2020
comment
Вот мой тест с вашим кодом. Когда вы нажимаете на любую из кнопок, вы получаете значение formTarget в $_POST. - person mikeroq; 30.11.2020
comment
Я вижу много веских причин для этого предложения, но я пытаюсь сделать эти функции как можно более универсальными, нет ли способа взять полный массив данных, отправленных в $_POST, и подставить его в эту строку вместо FormData? const form = new FormData(event.target) Я понимаю, что спецификация говорит, что FormData не должна знать о значениях отправки, но я не согласен со спецификацией и обходным путем, который противоречит цели всего набора универсальных функций. Не поймите меня неправильно, ваша помощь была отличной в диагностике реальной проблемы, и теперь я просто хотел бы упростить решение. - person FolioGraphic; 30.11.2020
comment
Для меня это просто неправильное использование формы. Я изменил JS в своем ответе, чтобы сделать его более универсальным. Он будет передавать любой атрибут data-* как данные POST на любой URL-адрес, определенный в data-url. Если вы хотите использовать форму для этого, вам придется использовать отдельную форму для каждой кнопки со скрытым вводом для вашего типа. Или вручную добавьте тип в FormData, прочитав значение кнопки. Я действительно предлагаю не использовать форму для этого. - person mikeroq; 30.11.2020
comment
Отдельная форма для каждого предложения кнопки была тем, что я использовал раньше. Когда я прорабатываю свой проект, я решил еще раз взглянуть на него, прежде чем завершить его, и отказался признать, что это лучшее решение. Как вы можете догадаться, каждый выбор, сделанный в этой форме, приводит к другой форме или выбору, и сохранение всего, связанного с одним и тем же JS, позволяет создавать сложные меню администратора без страницы за страницей, путаницы навигации для пользователя. Это мог быть флажок и отправка или радио и отправка, но я хотел кнопку для простоты. Это мой беспорядок, и ты помог мне заставить его работать. Спасибо! - person FolioGraphic; 30.11.2020
comment
Для протокола: ваше замечание об использовании кнопки вместо ссылки, оформленной в виде кнопки, принято и принято. Пример, который я разместил с этим вопросом, представляет собой случай, когда кнопки вообще не имеют ничего общего с полями формы, но цель всего этого уходит в более глубокое приложение, где поиск может привести к нескольким отображаемым результатам и нескольким формам отправки использует как: Открыть сведения о выбранном элементе или Удалить выбранные элементы. - person FolioGraphic; 01.12.2020