Despite the fact that this branch is older and the correct answer is given, for the benefit of beginners, as well as to explain the logic of deleting added lines.
Let me explain with a minimal code and example user with fields firstName, email, userName and gender.
Given that you send 3 empty users to usersList from the controller, this will create 3 empty lines. And now you want to add lines and dynamically link the added lines with modelAttribute.
(in the case of the initial 3 lines) If you inspect / view the source code of the page, you will see
- Lines (
<input> tags ) with a different identifier , like list0.firstName list1.firstName
- Strings (
<input> tags ) with different names , for example list[0].firstName list[1].firstName
Whenever a form is submitted, id's are not considered by the server (they are added only to help with client-side validation), but the name attribute will be interpreted as a request parameter and used to create your modelAttribute, therefore, attribute names are very important when inserting strings.
Adding a line
So how to build / add new lines?
If I send 6 users from the user interface, the controller should get 6 user objects from the user list. The steps to achieve the same are given below.
1. Right-click -> view page source . You will see such lines (you can see *[0].* In the first row and *[1].* In the second row)
<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>
- Copy the first line and create a javascript line and replace '0' with the variable name index. As indicated in the example below
'<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>';
- Add the constructed string to the
<tbody> . Lines are also added to the user interface when the form is submitted; new added lines will be received in the controller.
Delete row
Deleting a line is a bit more complicated, I will try to explain the easiest
- Suppose you add row0, row1, row2, row3, row4, row5
- Deleted row2, row3. Not just hide the line, but remove it from the DOM, catching the event.
- Now row0, row1, row4, row5 will be sent, but in your controller userList will have 6 user objects, but user [2] .firstName will be zero and user [3] .firstName will be zero.
- So in your iteration controller and check for a null value and delete the user. (Use an iterator, do not use foreach to delete a user object)
Posting code for beginners.
In 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 must be included in 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>'; }