即使这个帖子较旧并且回答正确,为了其他初学者的利益,也为了解释逻辑以实现删除添加的行。
让我用一个最小的代码和用户示例来解释 firstName、email、userName 和 gender 字段。
考虑到您从控制器发送用户列表中的 3 个空用户,这将创建 3 个空行。现在您要添加行并将添加的行动态绑定到 modelAttribute。
(如果是最初的 3 行)如果您检查/查看页面源代码,您将看到
- 具有不同 id 的行(
<input> tags),例如 list0.firstName
list1.firstName
- 具有不同名称的行(
<input> tags),例如list[0].firstName
list[1].firstName
每当提交表单时,服务器不会考虑 id 的(添加仅用于帮助客户端验证),但 name 属性 将被解释为请求参数并用于构造你的modelAttribute,因此属性名称在插入行时非常重要。
添加行
那么,如何构造/追加新行?
如果我从 UI 提交 6 个用户,控制器应该从 usersList 接收 6 个用户对象。下面给出了实现相同的步骤
1、右键->查看页面源代码。你会看到这样的行(你可以在第一行看到*[0].*,在第二行看到*[1].*)
<tr>
<td><input id="list0.firstName" name="list[0].firstName" type="text" value=""/></td>
<td><input id="list0.email" name="list[0].email" type="text" value=""/></td>
<td><input id="list0.userName" name="list[0].userName" type="text" value=""/></td>
<td>
<span>
<input id="list0.gender1" name="list[0].gender" type="radio" value="MALE" checked="checked"/>Male
</span>
<span>
<input id="list0.gender2" name="list[0].gender" type="radio" value="FEMALE"/>Female
</span>
</td>
</tr>
<tr>
<td><input id="list1.firstName" name="list[1].firstName" type="text" value=""/></td>
<td><input id="list1.email" name="list[1].email" type="text" value=""/></td>
<td><input id="list1.userName" name="list[1].userName" type="text" value=""/></td>
<td>
<span>
<input id="list1.gender1" name="list[1].gender" type="radio" value="MALE" checked="checked"/>Male
</span>
<span>
<input id="list1.gender2" name="list[1].gender" type="radio" value="FEMALE"/>Female
</span>
</td>
</tr>
- 复制第一行并构造一个 javascript 字符串并将“0”替换为变量名索引。如下示例所示
'<tr>'+
'<td><input id="list'+ index +'.firstName" name="list['+ index +'].firstName" type="text" value=""/></td>'+
'<td><input id="list'+ index +'.email" name="list['+ index +'].email" type="text" value=""/></td>'+
...
'</tr>';
- 将构造的行附加到
<tbody>。在 UI 中添加行也会在提交表单时在控制器中接收新添加的行。
删除行
删除行有点复杂,我会尝试用最简单的方式解释
- 假设您添加了 row0、row1、row2、row3、row4、row5
- 已删除第 2 行、第 3 行。不要只是隐藏该行,而是将其从
DOM 通过捕获事件。
- 现在 row0,row1,row4,row5 将被提交,但在控制器中您的
userList 将有 6 个用户对象,但 user[2].firstName 将为 null
并且 user[3].firstName 将为空。
- 因此在您的控制器中迭代并检查 null 并删除
用户。(使用迭代器不要使用 foreach 删除用户对象)
发布代码,让初学者受益。
// In Controller
@RequestMapping(value = "/app/admin/add-users", method = RequestMethod.GET)
public String addUsers(Model model, HttpServletRequest request)
{
List<DbUserDetails> usersList = new ArrayList<>();
ListWrapper userListWrapper = new ListWrapper();
userListWrapper.setList(usersList);
DbUserDetails user;
for(int i=0; i<3;i++)
{
user = new DbUserDetails();
user.setGender("MALE"); //Initialization of Radio button/ Checkboxes/ Dropdowns
usersList.add(user);
}
model.addAttribute("userListWrapper", userListWrapper);
model.addAttribute("roleList", roleList);
return "add-users";
}
@RequestMapping(value = "/app/admin/add-users", method = RequestMethod.POST)
public String saveUsers(@ModelAttribute("userListWrapper") ListWrapper userListWrapper, Model model, HttpServletRequest request)
{
List<DbUserDetails> usersList = userListWrapper.getList();
Iterator<DbUserDetails> itr = usersList.iterator();
while(itr.hasNext())
{
if(itr.next().getFirstName() == null)
{
itr.remove();
}
}
userListWrapper.getList().forEach(user -> {
System.out.println(user.getFirstName());
});
return "add-users";
}
//POJO
@Entity
@Table(name = "userdetails")
@XmlRootElement(name = "user")
public class DbUserDetails implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstName;
private String userName;
private String email;
private String gender;
//setters and getters
}
//list wrapper
public class ListWrapper
{
private List<DbUserDetails> list;
//setters and getters
}
在 JSP 中
<form:form method="post" action="${pageContext.request.contextPath}/app/admin/add-users" modelAttribute="userListWrapper">
<table class="table table-bordered">
<thead>
<tr>
<th><spring:message code="app.userform.firstname.label"/></th>
<th><spring:message code="app.userform.email.label"/></th>
<th><spring:message code="app.userform.username.label"/></th>
<th><spring:message code="app.userform.gender.label"/></th>
</tr>
</thead>
<tbody id="tbodyContainer">
<c:forEach items="${userListWrapper.list}" var="user" varStatus="loop">
<tr>
<td><form:input path="list[${loop.index}].firstName" /></td>
<td><form:input path="list[${loop.index}].email" /></td>
<td><form:input path="list[${loop.index}].userName" /></td>
<td>
<span>
<form:radiobutton path="list[${loop.index}].gender" value="MALE" /><spring:message code="app.userform.gender.male.label"/>
</span>
<span>
<form:radiobutton path="list[${loop.index}].gender" value="FEMALE" /><spring:message code="app.userform.gender.female.label"/>
</span>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="offset-11 col-md-1">
<button type="submit" class="btn btn-primary">SAVE ALL</button>
</div>
</form:form>
Javascript 需要包含在 JSP 中
var currentIndex = 3; //equals to initialRow (Rows shown on page load)
function addRow()
{
var rowConstructed = constructRow(currentIndex++);
$("#tbodyContainer").append(rowConstructed);
}
function constructRow(index)
{
return '<tr>'+
'<td><input id="list'+ index +'.firstName" name="list['+ index +'].firstName" type="text" value=""/></td>'+
'<td><input id="list'+ index +'.email" name="list['+ index +'].email" type="text" value=""/></td>'+
'<td><input id="list'+ index +'.userName" name="list['+ index +'].userName" type="text" value=""/></td>'+
'<td>'+
'<span>'+
'<input id="list'+ index +'.gender1" name="list['+ index +'].gender" type="radio" value="MALE" checked="checked"/>Male'+
'</span>'+
'<span>'+
'<input id="list'+ index +'.gender'+ index +'" name="list['+ index +'].gender" type="radio" value="FEMALE"/>Female'+
'</span>'+
'</td>'+
'</tr>';
}