即使这个线程较旧并且回答正确,为了其他初学者的利益,也为了解释逻辑以实现删除添加的行。
让我用一个最小的代码和用户示例来解释一下名字、电子邮件、用户名和性别字段。
考虑到您从控制器发送用户列表中的 3 个空用户,这将创建 3 个空行。现在您想要添加行并将添加的行动态绑定到 modelAttribute。
(如果是最初的 3 行)如果您检查/查看页面源代码,您将看到
<input> tags
具有不同id 的Rows( )喜欢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。
- 因此,在您的控制器中迭代并检查 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>';
}