所以问题是这样的:当您单击这些链接(保存或删除)时,您实际上并没有告诉服务器您正在更新什么。该链接本身无法知道它正在发送哪些字段,或者它们是否已更新,或任何其他信息。您正在页面上进行动态操作,在这种情况下,这将意味着脚本。
这比您使用切换功能所做的要复杂一个数量级,因此请注意 - 您刚刚跳入了最深的一端。我已经开始构建一些可以向您展示可以如何完成的东西,但这绝不是完整或准确的。通过您给我们的快照,我们不知道您的 php 到底在做什么。
这是我构建的代码块,只是作为原型。我将在下面更详细地描述它:
$(function(){
let updateTeamUrl = "SET_THIS_TO_THE_UPDATE_URL";
// We'll also save these as references to all the action buttons.
let actionItems = {
editBtn: $(".btnEdit"),
saveBtn: $(".save-btn"),
deleteBtn: $(".btnDelete")
}
$(".editshow").hide();
// Here we assign the actions to the various buttons/anchors
actionItems.editBtn.on("click", toggleEdit);
actionItems.saveBtn.on("click", saveTeam);
actionItems.deleteBtn.on("click", confirmDelete)
// Below are the actions we assign above, or support functions for them
/**
* toggleEdit() is triggered when the "Edit" button is clicked. This
* hides the team name text element, and displays the editable field.
**/
function toggleEdit(event){
let teamContainer = $(this).closest("tr");
teamContainer.find(".editshow").toggle();
teamContainer.find(".editable").toggle();
}
/**
* saveTeam() crawls up the DOM tree to the closest "tr" node, and gets
* the custom "data-teamid" attribute there. Using that, we can create
* a JSON object that we will send to the backend.
**/
function saveTeam(event){
event.preventDefault();
let clickedEl = $(this),
teamContainer = clickedEl.closest("tr"),
teamNameEl = teamContainer.find(".editshow");
let payloadToSend = {
// We need a mechanism to identify what team we're updating
teamId: teamContainer.data("teamid"),
// This will eventually hold any and all updates.
updates: {
/* We'll create this empty, and fill it as we need.*/
}
};
// I created a data attribute on the input, "data-original", and
// set it to the same value as the input. By comparing these, we
// can see if an input has, in fact, been updated.
if(teamNameEl.data("original") !== teamNameEl.val() ){
/**
* The only thing we are updating in this pass is the team name.
* So we can update our "payload", then simply send the post request.
**/
payloadToSend.updates.name = teamNameEl.val();
/**
* When we POST, we need a URL and a string we'll send.
* What we'll do is take the payload, and run it through
* JSON.stringify() to convert it to a string.
* Then, when we call $.post(), we can also add a .done() and
* .fail() handler. These will run when the save is complete,
* or when it fails.
*
**/
let postRequest = $.post(UpdateTeamUrl, JSON.stringify(payloadToSend) )
.done(function(returnedData){
console.log("Update succeeded: "+returnedData)
})
.fail(function(error){
console.error("Update had an error: "+error)
})
.always(function(){
teamContainer.find(".editshow").toggle();
teamContainer.find("editable").toggle();
});
}
} // end saveTeam();
function confirmDelete(event){
event.preventDefault();
let clickedEl = $(this),
teamContainer = clickedEl.closest("tr"),
teamId = teamContainer.data("teamid"),
teamName = teamContainer.find("[name='edit_teams']").val();
if(confirm("are you sure you want to delete the team "+teamId+": "+teamName+"?") ){
console.log("Deleting!")
} else {
console.log("false alarm.")
}
}
})
此外,支持此功能的 HTML 需要稍作更改:<tr> 获取数据属性 data-teamid,<input> 获取数据属性 data-original,包装输入的表单元素已删除。这是 HTML(没有 PHP 来构建它):
<tr data-teamid="1">
<td>
<a href='#' class='editable' style='margin-left: 2px;'>Team Name</a>: <input type='text' class='editshow form-control col-sm-3' aria-label='Sizing example input' aria-describedby='inputGroup-sizing-sm' name='edit_teams' data-original='Team Name' value='Team Name'> <a href='teams.php?save_tid={$tid}' style='margin-left: 2px; margin-top:3px;' class='btn btn-success btn-sm editshow save-btn'>Save</a>
</td>
<td>
<button class='btn btn-primary btn-sm btnEdit team-1'>Edit</button> | <a href='#' class='btn btn-danger btn-sm btnDelete'>Delete</a>
</td>
</tr>
正如我所说,这变得相当复杂。
首先,我将您所有的“操作”移到了一个 javascript 对象中。如果我添加其他操作,我只需在那里更新它们。然后,我使用.on(...) 为我要处理的每个操作附加侦听器:编辑、保存和删除。对于其中的每一个,我编写了一个函数来处理操作本身:toggleEdit(...) 用于编辑,saveTeam(...) 用于保存,confirmDelete 用于删除。每个动作都是独立的,使编辑更容易。
toggleEdit(...) 几乎与您之前的完全一样。我不认为我在那个方面有太大变化,所以看起来应该很熟悉。
saveTeam(...) 是您现在要询问的那个,它是复杂的位。首先,我们爬回 DOM 树到 <tr>,并使用 .data("teamid") 获取我们正在编辑的团队的 id。然后我们开始创建一个javascript 对象,我称之为payloadToSend。在此,我们有一个属性teamId,和一个嵌套对象updates。接下来,我们检查文本输入是否已更新(通过将其值与我添加的 data-original 属性进行比较)。如果它没有改变,我们不需要更新。如果它有,那么我们通过将name 添加到payloadToSend.updates 对象来更新payloadToSend,并且我们使用$.post(...) 来实际发送POST 请求。 $.post() 接受一个 URL 和一些数据。我们将发送payloadToSend 对象作为该数据,它应该在php 中显示为$_REQUEST 或$_POST。此外,$.post(...) 包括两个条件回调,.done(...) 和 .fail(...),以及一个“绝对”回调,.always(...)
.done(...) 在服务器端请求返回成功完成时运行,.fail(...) 处理后端失败并显示错误消息。不过,无论哪种情况,我们.always(...) 都希望隐藏可编辑项并再次显示团队名称。
此时,confirmDelete 操作除了获取相同的 teamId 并弹出一个基本的确认对话框之外没有做任何其他事情。删除操作远不止于此,超出了您最初问题的范围。