提问者:小点点

使用Ajax,JavaScript,PHP删除数据库条目


我对web编程很陌生,在创建一个简单的客户机数据库时遇到了一些问题。 我必须找到一种使用Ajax从数据库中删除客户机的方法。 我试图在不使用jQuery的情况下找到解决方案。。。 到目前为止,我设法设置了一个脚本和php代码来删除一个数据库条目; 但是,不可能在不首先刷新页面的情况下删除另一个客户端。 有人能帮我找出解决这个问题的办法吗?

my index.php中的相关部分

<?php
    require_once "CRM_DB.php";
    $clients = CRM_DB::showAll();
?>

...

<div class="container">

    <div class="row mb-4">
    <div class="col-sm-12">
        <h2>All Entries</h2>
        <table class="table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>E-Mail</th>
                    <th>Comment</th>
                    <th>Created At</th>
                    <th>Updated At</th>
                    <th>Delete</th>
                    <th>Edit</th>
                </tr>   
            </thead>
            <tbody>
                <? foreach($clients as $client): ?>
                    <tr id="table-row">
                        <td><?= $client->id ?></td>
                        <td><?= $client->name ?></td>
                        <td><?= $client->email ?></td>
                        <td><?= $client->text ?></td>
                        <td><?= $client->created_at ?></td>
                        <td><?= $client->updated_at ?></td>
                        <td>
                            <form action="" class="delete-form m-0" method="post">
                                <input type="hidden" id="del-id" name="id" value="<?= $client->id ?>">
                                <input type="hidden" name="delete" id="delete" value="1">
                                <button type="submit" class="btn btn-danger btn-sm" id="delete_btn" onclick="deleteID(); return false">Delete</button>
                            </form>
                    </tr>
                <? endforeach; ?>
            </tbody>
        </table>    

....

<script type="text/javascript">

    function deleteID() {

        var id = document.getElementById('del-id').value;
        var del = document.getElementById('delete').value;
        var params = 'delete='+encodeURIComponent(del)+'&id='+encodeURIComponent(id);
        var url = 'crm.php';

        xmlhttp = new XMLHttpRequest();

        xmlhttp.onload = function() {
            if(this.readyState == 4 && this.status == 200) {
                document.getElementById('table-row').innerHTML = this.response;
                    }
                };

        xmlhttp.open("POST", url, true);
        xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlhttp.send(params);
    }
</script>

crm.php

if(isset($_POST["delete"]) && isset($_POST["id"])) {
    $id = $_POST["id"];
    CRM_DB::deleteClient($id);
}

crm_db.php

    public static function deleteClient($id) {
        $db = self::db();

        $query = "DELETE FROM clients WHERE id = ?";
        $result = $db->query($query, [$id]);
        return $result;
    }

    public static function showAll() {
        $db = self::db();

        $query = "SELECT * FROM clients";
        $result = $db->query($query);

        $clientArray = [];

        for($i = 0; $i < $result->num_rows; $i++) {
            $row = $result->fetch_array();

            $client = self::convertToObject($row);
            $clientArray[] = $client;
        }
        return $clientArray;
    }

    public static function convertToObject($row) {
        return new Client($row["id"], $row["name"], $row["email"], $row["text"], $row["created_at"], $row["updated_at"]);
    }

}


共2个答案

匿名用户

我认为问题可能是,您正在为处的多个元素分配相同的元素ID。 起初,这不是有效的HTML。 元素ID在HTML中必须是唯一的。 其次,函数deleteID()不知道应该删除哪个客户端。 它只选择ID为“del-id”的(许多)HTML元素中的第一个元素。

解决方案:移除隐藏字段“del-id”,将客户端的ID作为函数参数传递,例如。

<button type="submit" class="btn btn-danger btn-sm" id="delete_btn" onclick="deleteID(<?= $client->id ?>); return false">Delete</button>

...

function deleteID(clientID) {
    var del = document.getElementById('delete').value;
    var params = 'delete='+encodeURIComponent(del)+'&id='+encodeURIComponent(clientID);
    var url = 'crm.php';
...
}

您也不需要传递参数“delete”,因为函数上下文已经是关于删除客户机的。 你可以把这个值硬核起来。

还有:永远不要相信用户的输入。 您应该检查clientID是否是有效的整数,以及用户是否具有删除客户端的权限!

匿名用户

ID属性必须是唯一的,如果处理不正确,通常会导致类似您在这里面临的问题。 在大多数情况下,我认为它们有更好的替代方案--使用parent/child/sibling类型选择器遍历DOM是完全可行的,使用document.QuerySelectordocument.QuerySelectorAll可以进一步增强这些选择器,以针对特定节点或节点集合。

如果您在循环中修改HTML的部分--为表行分配dataset属性并删除如下表单--请注意,表行的ID已更改为class属性,因此可能需要对css进行更改。 表单本质上什么也不做,因为输入元素被隐藏了,所以用户不能合法地修改值--所以当Ajax发送请求时,它可以被删除。

        <tbody>
            <? foreach($clients as $client): ?>
                <tr class="table-row" data-id='<?=$client->id;?>'>
                    <td><?= $client->id ?></td>
                    <td><?= $client->name ?></td>
                    <td><?= $client->email ?></td>
                    <td><?= $client->text ?></td>
                    <td><?= $client->created_at ?></td>
                    <td><?= $client->updated_at ?></td>
                    <td>
                        <button type="button" class="btn btn-danger btn-sm">Delete</button>
                    </td>
                </tr>
            <? endforeach; ?>
        </tbody>

然后您可以修改javascript以删除内联事件处理程序并创建一个单独的ajax函数

<script>

    const url='crm.php';

    const callback=function(r,id){
        let tr=document.querySelector('tr[data-id="'+id+'"]');
        let l=tr.childNodes.length || 7;
            tr.innerHTML='';

        let td=document.createElement('td');
            td.setAttribute('colspan',l);
            td.textContent=r;

        tr.appendChild( td );
    };

    const ajax=function(url,params,callback){
        let query=Object.keys( params ).map( k=>{
            return [ k, params[k] ].join('=');
        }).join('&');

        let xmlhttp = new XMLHttpRequest();
            xmlhttp.onload = function() {
                if( this.readyState == 4 && this.status == 200 ) {
                    callback( this.response, id );
                }
            };
            xmlhttp.open( 'POST', url, true );
            xmlhttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
            xmlhttp.send( query );          
    };


    Array.from( document.querySelectorAll('tr.table-row > td > button.btn-danger') ).forEach( bttn=>{
        bttn.addEventListener('click',function(e){
            /* create the payload for this row */
            let params={
                'id':this.parentNode.parentNode.dataset.id,
                'delete':true
            };

            /* call the ajax function with collected parameters */
            ajax( url, params, callback )
        });
    });
</script>