我对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"]);
}
}
我认为问题可能是,您正在为处的多个元素分配相同的元素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.QuerySelector
和document.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>