首页 > 解决方案 > JavaScript Fetch() 不区分表单的更新和删除功能

问题描述

我有一个当前在服务器上使用 PHP/MySQL 处理的表单,它在前端使用 JavaScript fetch() API,这样当详细信息提交到数据库时,页面不会在表单提交时重新加载。

表单本身位于一个循环中,该循环将表单的多个实例输出到页面上。

为了使 JavaScript 工作,它依赖于以下 PHP(我将在问题末尾显示更详细的代码)

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    // PHP to process form details
}

javascript是:

var forms = document.querySelectorAll('form');

forms.forEach(item => {
    
    item.addEventListener("submit", function (evt) {
    
        evt.preventDefault();

        const formData = new FormData(this);

        fetch("upload-details.php", {
            method: 'post',
            body: formData
        }).then(function(response){
            return response.text();
        }).catch(function (error){
            console.error(error);
        })

        // remove item after form details submitted
        item.remove();

    })

})

我现在希望添加一个也适用于 JS fetch API 的删除按钮。我遇到的问题是,我无法让 JS Fetch 区分何时更新表单详细信息和何时删除记录?

我试过改变这个:

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    // PHP to process form details (both update and delete)
}

为此(无济于事):

if(isset($_POST['update'])) {
    // PHP to process form details
}

if(isset($_POST['delete'])) {
    // PHP to process form details
}

当我关闭 JS fetch() API 代码时,从 PHP / MySQL 的角度来看,下面的代码的行为完全符合预期(即它相应地更新和删除记录)。

更详细的代码:

<?php
isset($_REQUEST['username']) ? $username = $_REQUEST['username'] : header("Location: login.php");

// the following variable is already fetched with PHP from the database
// it is added as a value to a hidden input element in the HTML form shown below
$db_image_id = htmlspecialchars($row['image_id']);

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    
    $image_title = $_POST['image-title'];
    $image_tags = $_POST['image-tags'];
    $image_id = $_POST['image-id']; // value attribute from hidden form element

    if(empty(trim($image_title))){
        $error[] = "Image Title cannot be blank";
    }

    if (!isset($error)) {

        try {

            $sql = "UPDATE imageposts SET
            image_title = :image_title,
            image_tags = :image_tags

            WHERE image_id = :image_id";
                
            $stmt = $connection->prepare($sql);
    
            $stmt->execute([
                ':image_title' => $image_title,
                ':image_tags' => $image_tags,
                ':image_id' => $image_id
            ]);
                    
        } catch (PDOException $e) {
            echo "Error: " . $e->getMessage();
        }

    } else {
        // give values an empty string to avoid an error being thrown before form submission if empty
        $image_title = $image_tags = "";
    }

}

//---- DELETE DETAILS
if(isset($_POST['upload-details-delete'])) {

    $image_id = $_POST['image-id']; // 'value' attribute from hidden form element

    try {

        $sql = "DELETE FROM `lj_imageposts` WHERE image_id = :id";
            
        $stmt = $connection->prepare($sql);

        $stmt->execute([
            ':id' => $image_id
        ]);
                
    } catch(PDOException $e) {
        echo "Error: " . $e->getMessage();
    }

}

// data is fetched with PHP to add to the form 
//(I haven't included this code because there is a lot of values outputted onto the form, and when the JavaScript fetch() is turned off it all works OK)
while ($row = $stmt->fetch()) {

?>

<!-- form that holds the update and delete elements -->
<div class="upload-details-component">
    <form method="post" enctype="multipart/form-data">
        <button name="delete">Delete</button>
        <div class="upload-details-image-wrapper">
            <!-- ** image is outputted here from database ** -->
        </div>
        <div class="edit-zone">
            <div class="form-row">
                <label>Image Title</label>
                <input type="text" name="image-title" placeholder="Image Title" >
            </div>
            <div class="form-row">
                <label>Image Tags</label>
                <textarea type="text" name="image-tags"></textarea>
            </div>
            <div class="form-row">
                <input type="submit" name="upload" value="COMPLETE UPLOAD">
            </div>
        </div>
        <input type="hidden" name="image-id" value="<?php echo $db_image_id?>">
    </form>    
</div>

<?php } ?>

标签: javascriptphpformsfetch-api

解决方案


仅当用户单击它时才添加到 POST 数据中的提交按钮。由于您在 javascript 中收集表单数据,因此不会单击任何按钮,因此不包括它们。

您需要做的是找出单击了哪个提交按钮,并在收集表单数据之前手动添加带有此类信息的隐藏输入字段,或者注入表单数据本身:

var forms = document.querySelectorAll('form');

forms.forEach(item => {

  item.addEventListener("submit", function(evt) {

    evt.preventDefault();

    const formData = new FormData(this);
    formData.set(evt.submitter.name, evt.submitter.value);

    console.log([...formData].join("|"));

  })

})
<form>
  <input name="test" value="blah">
  <input type="hidden" name="hid" value="hidblah">
  <button type="submit" name="update" value="upd">update</button>
  <button type="submit" name="delete" value="del">delete</button>
</form>

由于并非所有浏览器都支持event.submitter,因此您需要通过 onclick 事件跟踪单击了哪个按钮:

var forms = document.querySelectorAll('form');

forms.forEach(item => {

  item.querySelectorAll('[type="submit"], button').forEach(button => {
    button.addEventListener("click", e => item._button = button); //store this button in the form element
  })

  item.addEventListener("submit", function(evt, btn) {

    evt.preventDefault();

    const formData = new FormData(this);
    if (this._button) //submitted by a button?
    {
      formData.set(this._button.name, this._button.value);
      delete this._button; //this only needed if form can be submitted without submit button (aka submitted by javascript)
    }

    console.log([...formData].join("|"));
  });
})
<form>
  <input name="test" value="blah">
  <input type="hidden" name="hid" value="hidblah">
  <button type="submit" name="update" value="upd">update</button>
  <button type="submit" name="delete" value="del">delete</button>
  <button name="submit" value="sub">submit</button>
</form>
<form>
  <input name="test2" value="blah2">
  <input type="hidden" name="hid2" value="hidblah2">
  <button type="submit" name="update2" value="upd2">update2</button>
  <button type="submit" name="delete2" value="del2">delete2</button>
  <button name="submit2" value="sub2">submit2</button>
</form>


推荐阅读