1

Sorry if this has been asked somewhere else, but I have looked all around, found some answers, but not a complete example and I am still in doubts on this one.

So, I am adding an Autopopulating list from my Spring controller to my jsp and I would like to add items on the list inside my javascript/jquery function. Is it possible?

I tried the code below to test the functionality but it did not work (the list elements did not show up at all at the generated html). So Im unsure if Im messing up with the javascrit/spring/jsp syntax or if it is just not possible.

Here is the code:

Controller code:

@RequestMapping(value="/create_custobject.html",method = RequestMethod.GET)
public ModelAndView showCreateCustObjectPage() {
    Map<String, Object> model = new HashMap<String, Object>();

    CreateObjectForm form = new CreateObjectForm();
    model.put("createObjectform", form);

    return new ModelAndView("create_custobject", model) ;

}

Form code:

public class CreateObjectForm {

      private AutoPopulatingList<Criteria> ruleArray = new AutoPopulatingList<Criteria>(Criteria.class);

     public AutoPopulatingList<Criteria> getRuleArray() {
    return ruleArray;
        }

         public void setRuleArray(AutoPopulatingList<Criteria> ruleArray) {
    this.ruleArray = ruleArray;
        }

         public CreateObjectForm() {}
      }

Criteria code:

public class Criteria{

   String attribute;

    String operator;
       //... constructor + getters and setters
}

javascript/jquery code (on the same page as the jsp one):

<script type="text/javascript">
$(document).ready(function(){
    //startup functionality

 var i = 0;
 document.getElementById("addCriteria").onclick = function() {

         $("#msgid").html("${ruleArray[i].attribute}");

        ${ruleArray[i].attribute} = $('#attributeValue').val();             
        ${ruleArray[i].operator} = $('#operatorValue').val(); 

                    i++;            

      }
   }
Thomas
  • 2,751
  • 5
  • 31
  • 52

4 Answers4

3

for existing items in your form use jstl as

<c:forEach items="${form.items}" var="item" varStatus="status" >
<span class="count" > 
<form:input   path="items[${status.index}].field" />

this will render form like this

<form id = "idform" >
<span class="count" > 
    <input   name="items[0].field"  id="items0.field" />
</span>
</form>

then you simply add with javascript new form "lines" with coresponding indexes

for example

 var is = $('.count').size()
 $('#idform span:last').after('<span class="count" ><input name="items[' + is + '].field"' + is + '.field" /></span>')

I think that if you are using spring 3 + you don't need to use AutopopulatingList , Any collection should be enough.

Josef Prochazka
  • 1,273
  • 2
  • 9
  • 28
1

Your mixing JSP EL and Javascript improperly. You cannot use the var i within a JSP expresssion, ie. ${ruleArray[i].operator}. I would recommend using JSTL to iterate through the list and create your attributes within the script.

At this point your script could be setup to just use a string literal 0 within the expression. I am assuming you need more robust functionality than this, can you describe it better.

$(document).ready(function(){
     document.getElementById("addCriteria").onclick = function() {

     $("#msgid").html("${ruleArray[0].attribute}");

     //I assume you wanted to set the element to the value pulled from JSP EL
     $('#attributeValue').val(${ruleArray[0].attribute});           
     $('#operatorValue').val(${ruleArray[0].operator});           

     }
 }

Using JSTL a solution would look something like:

<script>
 var criteria = [];
 <c:forEach var="criteria" items=${ruleArray}>
    criteria.push({attr:${criteria.attribute}, oper: ${criteria.operator});
 </c:forEach>

 for(var i = 0; i < criteria.length; i++){
  alert(criteria[i].attribute);
 }
</script>

This solution basically uses JSTL to write Javascript. It may be a better solution to modify your controller to return JSON and just make an Ajax call on page load.

Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • I cleaned up the code a bit (add an "i" iteration), but well basically I would like to add new items in the autopopulating list in the javascript code and get the list back when the post is done. I cant use jstl inside the javascript right? – Thomas Nov 13 '12 at 10:43
  • @Thomas: no you can't if you expect your code to be executed on the client side. – Yevgeniy Nov 13 '12 at 10:53
0

in the following line you are referencing i in your jsp-code, but i is not defined:

$("#msgid").html("${ruleArray[i].attribute}");

the javascript code which defines i is executed on the client (i.e. browser). The jsp-code is executed on the server, before the rendered html is sent to the client.

Yevgeniy
  • 2,614
  • 1
  • 19
  • 26
0

Even though this thread is older and is answered correctly, For the benefit of others who is beginners and also to explain logic to achieve deletion of added rows.

Let me explain with a minimal code and User example with firstName, email, userName and gender fields.
Considering you are sending 3 empty users in usersList from controller this will creates 3 empty rows. And now you want to add rows and bind the added rows to modelAttribute dynamically.

(in case of initial 3 rows)If you inspect/view page source you will see

  • Rows(<input> tags) with different id's like list0.firstName list1.firstName
  • Rows(<input> tags) with different names like list[0].firstName list[1].firstName

Whenever form is submitted id's are not considered by server(added for only for helping client side validations) but name attribute will be interpreted as request parameter and are used to construct your modelAttribute, hence attribute names are very important while inserting rows.

Adding row

So, How to construct/append new rows?
If i submit 6 users from UI, controller should receive 6 user object from usersList. Steps to achieve the same is given below
1. Right click -> view page source. You will see rows like this(you can see *[0].* in first row and *[1].* in 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>
  1. Copy first row and construct a javascript string and replace '0' with variable name index. As given in below sample
'<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>';
  1. Append the constructed row to the <tbody>. Rows get added in UI also on submission of form newly added rows will be received in controller.

Deleting row

Deleting row is little bit complicated, i will try to explain in easiest way

  • Suppose you added row0, row1, row2, row3, row4, row5
  • Deleted row2, row3. Do not just hide the row but remove it from the DOM by catching event.
  • Now row0,row1,row4,row5 will get submitted but in the controller your userList will have 6 user object but user[2].firstName will be null and user[3].firstName will be null.
  • So in your controller iterate and check for null and remove the user.(Use iterator don't use foreach to remove user object)

Posting code to benefit beginners.

//  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
}

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 needs to 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>';
}
PraveenKumar Lalasangi
  • 3,255
  • 1
  • 23
  • 47