views:

167

answers:

3

Ok so perhaps someone can help me with a problem I'm trying to solve. Essentially I have a JSP page which gets a list of Country objects (from the method referenceData() from a Spring Portlet SimpleFormController, not entirely relevant but just mentioning in case it is). Each Country object has a Set of province objects and each province and country have a name field:

public class Country  {
    private String name;
    private Set<Province> provinces;

    //Getters and setters
}

public class Province {
    private String name;

    //Getters and setters
}

Now I have two drop down menus in my JSP for countries and provinces and I want to filter the provinces by country. I've been following this tutorial/guide to make a chain select in JavaScript.

Now I need a dynamic way to create the JavaScript array from my content. And before anyone mentions AJAX this is out of the question since our project uses portlets and we'd like to stay away from using frameworks like DWR or creating a servlet. Here is the JavaScript/JSP I have so far but it is not populating the Array with anything:

var countries = new Array();
<c:forEach items="${countryList}" var="country" varStatus="status">
    countries[status.index] = new Array();
    countries[status.index]['country'] = ${country.name};
    countries[status.index]['provinces'] =
    [
        <c:forEach items="${country.provinces}" var="province" varStatus="provinceStatus">
            '${province.name}'
            <c:if test="${!provinceStatus.last}">
              ,
            </c:if>
        </c:forEach>
    ];
</c:forEach>

Does anyone know how to create an JavaScript array in JSP in the case above or what the 'best-practice' would be considered in this case? Thanks in advance!

+2  A: 

Have you considered using JSON? There are several libraries out there that can take a generic collection and output JSON for Java and other languages.

Ben S
I deleted a comment wherein I said this was not useful - I realize that it really *could* be useful if the Java classes here are appropriate. By converting to a JSON string, you could then just output the string and be done. However, note that JSON is a restricted form of full-blown Javascript objecct notation, so for some kinds of data it might not work so well. **Very** convenient if it does work, however. I always have a `pointy:toJSON()` EL function in my apps :-)
Pointy
+2  A: 
var countries = new Array();
<c:forEach items="${countryList}" var="country" varStatus="status"> 
    countryDetails = new Object();
    countryDetails.country = ${country.name}; 
    var provinces = new Array();

        <c:forEach items="${country.provinces}" var="province" varStatus="provinceStatus"> 
           provinces.push(${province.name});
        </c:forEach> 
    countryDetails.provinces = provinces;
    countries.push(countryDetails);
</c:forEach> 

now what you have is something like this in javascript

var countries = [
  {country:"USA",
  provinces: [
    "Ohio",
    "New York",
    "California"
  ]},
  {country:"Canada",
  provinces: [
    "Ontario",
    "Northern Territory",
    "Sascetchewan"
  ]},
]

The other option would be to make your output look like the javascript I posted.

var countries = [
<c:forEach items="${countryList}" var="country" varStatus="status">  
    {country: '${country.name}',
    provinces : [ 
        <c:forEach items="${country.provinces}" var="province" varStatus="provinceStatus">  
           '${province.name}'
           <c:if test="${!provinceStatus.last}">    
             ,    
           </c:if>   
        </c:forEach>  
    ]}
    <c:if test="${!status.last}">    
      ,    
    </c:if>  
    </c:forEach>  
];
John Hartsock
The second one would result in considerably less code being generated, so I'd definitely go that route.
Pointy
Sweet, thanks! I'm having a problem with my Controller getting the countries but this was exactly what I was looking for...thanks again! I ended up going with the second solution that produces JSON in case anyone was wondering.
tkeE2036
Glad I could help.
John Hartsock
+1  A: 

The primary problem in your code is that you forgot to put "status.index" inside ${ }.

countries[${status.index}] = new Array();

Now, that said, that would be a pretty bad way to do things because you'd end up with a lot of Javascript code in your page. Much much better to create the list using Javascript object notation as in the second of @John Hartsock's answers.

Pointy