Confused about using grails paginate - java

I am new to grails and I am a bit confused about how to use <g:paginate>.
I have a table and I want to set the max number of entrees to 10. Most of the examples I find online have used a List and have a set of jobs and services that help create the navigation. I am confused about this because I did not use a list in my controller. The total number of entrees is going through, but every entree is still displayed. If I click on page 2 or a 'next' button, it seems that my controller loses track of the sourceVolume that the user selected to generate this list.
For context - the first page the user sees prompts them to select a source volume - and from there a table is generated that shows a list of all of the entrees(snapshots) in the source volume.
my selectSnapshotVolume.gsp
<g:form class = "myForm" url="[controller:'Vaultrecovery', action:'doRecoveryConfirmation', method:'post']">
<table class = "content-table">
<thead>
<tr>
<th>Select</th>
<th>Cluster</th>
<th>Vserver</th>
<th>Volume</th>
<th>SnapShot</th>
</tr>
</thead>
<tbody>
<g:each in="${destinationVolumes}" var="destinationVolume">
<tr>
<td><g:radio name="snapshot" value="$destinationVolume.snapshot" required="true"></g: radio></td>
<td>
${destinationVolume.cluster}
</td>
<td>
${destinationVolume.vserver}
</td>
<td>
${destinationVolume.volume}
</td>
<td><b>
${destinationVolume.snapshot}
</b></td>
</tr>
<g:hiddenField name="cluster" value="${destinationVolume.cluster}" />
<g:hiddenField name="vserver" value="${destinationVolume.vserver}" />
<g:hiddenField name="volume" value="${destinationVolume.volume}" />
</g:each>
</tbody>
</table>
<div class = "centerMe">
<div class="pagination">
<g:paginate controller='Vaultrecovery' total="${entreeCount.total[0] ?: 0}" />
</div>
</div>
<div class = "centerMeDescription">
<g:submitButton class="submit " name="submit" value="Submit"/>
</div>
</g:form>
and here is my controller. I do not have any services, jobs, or a domain class. I have also cut out parts of the controller that are irrelevant.
class VaultrecoveryController {
def dataSource_model // netapp_model
def dataSource // dataautomation
def mailService
File testFile = new File("/opt/tomcat/work/TEST")
boolean TEST = testFile.exists()
def index() { }
def selectSourceVolume() {
log.info "Vaultrecovery Controller - selectSourceVolume"
def foo = new Sql(dataSource_model)
String SQL
SQL = "SELECT distinct(name) FROM volume WHERE (name NOT LIKE '%_dest%' AND name NOT LIKE 'MDV%' AND name NOT LIKE '%\\_\\_%') ORDER BY name"
log.info "Getting source volumes: " + SQL
def sourceVolumes = foo.rows(SQL)
[sourceVolumes: sourceVolumes]
} // end selectSourceVolume
def selectSnapshotVolume() {
log.info "Vaultrecovery Controller - selectSnapshotVolume"
def sourceVolume = params.srcvolume
log.info "SOURCE VOLUME IS: " + sourceVolume
def foo = new Sql(dataSource)
String SQL
SQL = "SELECT cluster, vserver, volume, snapshot FROM netapp_vault WHERE volume LIKE '%" + sourceVolume + "%' ORDER BY snapshot"
log.info SQL
def destinationVolumes = foo.rows(SQL)
SQL = "SELECT COUNT(cluster) as total FROM netapp_vault WHERE volume LIKE '%" + sourceVolume + "%' ORDER BY snapshot"
def entreeCount = foo.rows(SQL);
[sourceVolume: sourceVolume, destinationVolumes: destinationVolumes, entreeCount: entreeCount]
} // end selectSnapshotVolume
}

You lost the search criteria because the Prev or the Next button did not POST your Source Volume value back to the controller.
I had the same problem in my project. Took me half the day to figure it out. If you check the HTML what the Prev and the Next button is, they only POST back the Max and Offset values back to the controller. Keep this in mind. This kind of project is state-less. So, your action will reset back to the initial state.
Next
I use a private variable to store my last used search criteria. My action checks if the private variable has anything. If so, it use the criteria from the private variable to run the SQL. So, I will get the same records from the page before. I then apply the Max and Offset to get the correct records.
Something like this:
class BookController {
private String _searchString = ''
def index() {
_searchString = (params.searchString == null) ? _searchString : params.searchString
bookList = Book.findAllByName(_searchString, params)
}
}
params.searchString will be null because the Prev/Next button does not POST back the searchString. If it is null, I grab the searchString from the private variable _searchString and use it in my dynamic finders. I am lucky that Grails did not reset the _searchString variable when the Prev/Next calls the action.

Related

If else not working on the basis of user selection

I am working on HTML tables. For that I am returning JSON from my Java code. I have a UI as HTML page where there is a form having from date to date and a select tag having 4 options like this
<form id="formId" method="get">
<div class="container">
<h4>Start Date:</h4>
<input type="text" id="startdate" name="fromdate" width="276"
placeholder="dd/mm/yyyy" required />
<h4>End Date:</h4>
<input type="text" id="enddate" name="todate" width="276"
placeholder="dd/mm/yyyy" required />
<h4>Outlets:</h4>
<select name="outlet" id="all">
<option>ALL</option>
<c:forEach var="item" items="${obj.outlet}">
<option>${item}</option>
</c:forEach>
</select>
<br>
<br>
<div>
<button id="button" class="btn btn-default" type="submit">Search</button>
</div>
</div>
</form>
I am taking that input from the form and getting values in the servlet in doget method like below:
String fromdate=request.getParameter("fromdate");
String todate=request.getParameter("todate");
String outlet=request.getParameter("outlet");
// System.out.println(String.format("fromdate: %s, todate: %s, outlet: %s", new Object[]{fromdate, todate, outlet}));
List<String> outletList = Arrays.asList(outlet.split("\\s*,\\s*"));
try {
String json = HourlySalesDateOutlet.createJson(outletList, fromdate, todate);
response.getWriter().write(json);
// System.out.println("dheeraj"+json);
}
catch (Exception e) {
e.printStackTrace();
}
}
Now here is my Java class where I have written two queries one for if the user selects all and other if user select specific outlet. My problem is the if statement is not executing only else is executing if the user selects one outlet from FORM if the user selects ALL then it's not working.
Below is my code:
public static String createJson(List<String> outletList, String startDate, String endDate) throws Exception {
Connection con = null;
String query1;
List<Map<String, String>> mapList = new LinkedList<Map<String, String>>();
String outletStr = outletList.stream().collect(Collectors.joining("','", "('", "')"));
if (outletList.equals("ALL")) {
query1 = "SELECT a.OUTLET,b.CUSTOMERDESCRIPTOR,a.BILLDATE,HOUR(a.BILLTIME) AS HOURS, SUM(a.NETAMOUNT) AS AMOUNT FROM SYNCBILL a,ecustomer b WHERE a.OUTLET=b.CUSTOMERIDENTIFIER AND a.CANCELLED<>'Y' AND a.BILLDATE BETWEEN STR_TO_DATE(REPLACE('"
+ startDate + "','/','.'),GET_FORMAT(DATE,'EUR')) AND STR_TO_DATE(REPLACE('" + endDate
+ "','/','.'),GET_FORMAT(DATE,'EUR')) GROUP BY OUTLET,BILLDATE,HOUR(BILLTIME)";
System.out.println("all"+query1);
} else {
query1 = "SELECT a.OUTLET,b.CUSTOMERDESCRIPTOR,a.BILLDATE,HOUR(a.BILLTIME) AS HOURS, SUM(a.NETAMOUNT) AS AMOUNT FROM SYNCBILL a,ecustomer b WHERE a.OUTLET=b.CUSTOMERIDENTIFIER AND b.CUSTOMERDESCRIPTOR in "
+ outletStr + " AND a.CANCELLED<>'Y' AND a.BILLDATE BETWEEN STR_TO_DATE(REPLACE('" + startDate
+ "','/','.'),GET_FORMAT(DATE,'EUR')) AND STR_TO_DATE(REPLACE('" + endDate
+ "','/','.'),GET_FORMAT(DATE,'EUR')) GROUP BY OUTLET,BILLDATE,HOUR(BILLTIME)";
System.out.println("2"+query1);
}
try {
con = DBConnection.createConnection();
PreparedStatement ps = con.prepareStatement(query1);
ResultSet rs = ps.executeQuery();
Map<RecordKey, Long> mapData = getMapList(rs);
}
I am not posting the full Java code. What I want is if the user selects all then if statement should execute and the query in it should execute. If the user selects else, then other should work, and here in my code only else is working if is not executing.
How can I debug this?
I have a simple solution for your problem. When user selects all, then in that case pass the empty list and while making the query just put this condition.
if (outletList.size()==0) {
// case for all
} else {
// do regular stuff
}
As pointed out in the comments, you're not comparing comparable types. outletList is a List and it can't be equated to a String even though the list may only contain a single element that happens to be a String. So, outletList.equals("ALL") doesn't do what you think it does.
But that raises an interesting point. You have a select list which isn't multiple so why return a list of what is always a single value? And why switch to sending back an empty list when ALL is selected? That doesn't make sense; there was a single selection made as expected. This adds unnecessary confusion.
Try instead sending back the single value as a String and letting that value determine the logic so you have flexibility. If it's not possible to avoid the list then accept only a single value (list[0] for example) and call equals on that not the List.
if(outletList[0].equals("All")) {...}
If you later find yourself in a situation where you need more than a single if-else pair, you can switch to a switch like so:
switch(outletList[0]) { // or the single value...
case "ALL":
...
...
default:
...
}

How to check a radio button with Selenium WebDriver Reading data from excel

I am using Coded UI for creating some test cases for a web application, while doing the same I have encountered an issue. I am not able to select a Radio Button using their Displayed Text, however if I use the ValueAttribute then its working fine. But, since value attribute is not containing a number which may not be of any logical use for a person creating test data, so I need to do same work using the Displayed Text of the Radio button.
Here is my html code
<td><input id="ContentPlaceHolder1_rbl_NewChanged_0" type="radio" name="ctl00$ContentPlaceHolder1$rbl_NewChanged" value="1131">
<label for="ContentPlaceHolder1_rbl_NewChanged_0">New</label></td>
<td><input id="ContentPlaceHolder1_rbl_NewChanged_1" type="radio" name="ctl00$ContentPlaceHolder1$rbl_NewChanged" value="1132">
<label for="ContentPlaceHolder1_rbl_NewChanged_1">Changed</label></td>
<td><input id="ContentPlaceHolder1_rbl_NewChanged_2" type="radio" name="ctl00$ContentPlaceHolder1$rbl_NewChanged" value="1133">
<label for="ContentPlaceHolder1_rbl_NewChanged_2">Longstanding</label></td>
I have tried the following code. but didn't work
String selectType = data.getType().get(rowCnt);// data reading from excel stored to string variable
List<WebElement> type = driver.findElements(By.xpath("//input[#type='radio']"));
for (int i = 0; i < type.size(); i++) {
if (type.get(i).getText().equals(selectType)) {
type.get(i).click();
}
}
If you are getting the String values pertaining to the text of the <label> tags e.g. New, Changed, Longstanding. etc from excel then you can write a function which will acccept the texts as String as follows:
public void clickItem(String itemText)
{
driver.findElement(By.xpath("//td//label[starts-with(#for,'ContentPlaceHolder1_rbl_NewChanged_')][.='" + itemText + "']")).click();
}
Now you can call the function clickItem() by passing the String argument to click on the relevant Radio Button as follows:
String selectType = data.getType().get(rowCnt); // data reading from excel stored to string variable
clickItem(selectType); // will support clickItem("New"), clickItem("Changed") and clickItem("Longstanding")
Note: As per the HTML you have provided the clickItem() method should work with the implemented Locator Strategy. As an alternative you can also replace the clickItem() function to click on the <input> node as follows:
public void clickItem(String itemText)
{
driver.findElement(By.xpath("//td//label[.='" + itemText + "']//preceding::input[1]")).click();
}

How can I filter the result given by c:forEach using the value selected in a drop down?

Following is my jsp code.
<c:forEach items="${nameList}" var="studentList">
<tr>
<td style="padding-bottom: .5em;">
<a id="student" href="number?regNo=<c:out value="${studentList.regNo}"/>">
<span class="eachStudent">
<span class="studentName"><c:out value="${studentList.name}"/></span><br/>
<span class="collName"><c:out value="${studentList.collName}"/></span><br/>
<span class="deptName"><c:out value="${studentList.deptName}"/></span><br/>
</span>
</a>
</td>
</tr>
</c:forEach>
The above c:forEach lists
Name CollName DeptName
ABCD coll1 dept1
kfkdb coll1 dept2
jbdd coll2 dept3
Following is the code that lists the collName and deptName respectively.
<div>
Filter students by College (not required):
<select id="byCollege" name="byCollege" >
<c:forEach items="${uniqueCollList}" var="uniqueCollList">
<option value="${uniqueCollList}"/>
${uniqueCollList}</option >
</c:forEach >
</select >
</div>
<div>
Filter students by Department Name (not required):
<select id="byDept" name="byDept" >
<c:forEach items="${uniqueDeptList}" var="uniqueDeptList">
<option value="${uniqueDeptList}"/>
${uniqueDeptList}</option >
</c:forEach >
</select >
</div>
Now when I select a value from first dropdown, I want to filter the results given by foreach using the value selected in dropdown. I would like to do this in front end itself, rather going to the back end. May I know how can I do this?
After filtering the c:foreach result using value of first dropdown, if I select a value in second dropdown, I want the updated result of c:foreach to be filtered using the value selected in second drop down.
How can I do this?
If I want to do this in back end, what should I do?
PS:Following is the controller code that sends the list first time
#RequestMapping(value = "/name", method = RequestMethod.POST, params = { "studentName" })
public String searchStudentByCollOrDept(#RequestParam(value = "studentName", required = true)String studentName, ModelMap model){
List<OneStudentResult> nameList = resultService.getStudentList(studentName);
//TODO, null value check.
if(nameList.size() == 0 || nameList == null){
return "header";
}
if(nameList.size() != 0){
// Iterate the list that we get and add only one time a collName and deptname.So a Treeset.
Set<String> uniqueCollList = new TreeSet<String>();
Iterator<OneStudentResult> itr = nameList.iterator();
while(itr.hasNext()){
String collName = itr.next().getCollName();
if(!uniqueCollList.contains(collName)){
uniqueCollList.add(collName);
}
}
uniqueCollList.add(" Select a College ");
model.addAttribute("uniqueCollList", uniqueCollList);
Set<String> uniqueDeptList = new TreeSet<String>();
Iterator<OneStudentResult> itrDeptList = nameList.iterator();
while(itrDeptList.hasNext()){
String deptName = itrDeptList.next().getDeptName();
if(!uniqueDeptList.contains(deptName)){
uniqueDeptList.add(deptName);
}
}
uniqueDeptList.add(" Select a Department ");
model.addAttribute("uniqueDeptList", uniqueDeptList);
}
model.addAttribute("nameList", nameList);
return "nameResult";
}
I'm afraid there is no simple solution to your problem. You should consider doing this server-side with ajax updates. Client side filtering would either require you to parse the data from the HTML generated by your studentList or it would require you to inject the data as a JSON formatted array. In both cases you would end up with doubled data (server & client). Having the data on the client-side would only allow you to disable some of the option values, not hide them. So if you want real filtering in terms of not-showing some of the options then you should filter your lists on the server. To do so you should post the selected option from your first dropdown "byCollege" to your backend in order to retrieve a filtered "uniqueDeptList" that you use to rebuild the "byDept" checkbox. You might want to use jQuery for both tasks.
Steps:
1. Handle the change-event of the "byCollege" dropdown
2. Post the selected option value to your servlet
3. Filter the data in your servlet and return the filtered data as POST response (omitted in this example)
4. Remove the old select options and recreate them from the filtered data
$("#byCollege").change(function() {
$("select option:selected").first().each(function() {
// Get and convert the data for sending
// Example: This variable contains the selected option-text
var outdata = $(this).text();
// Send the data as an ajax POST request
$.ajax({
url: "yourjsonservlet",
type: 'POST',
dataType: 'json',
data: JSON.stringify(outdata),
contentType: 'application/json',
mimeType: 'application/json',
success: function(data) {
// Remove old select options from the DOM
$('#byCollege')
.find('option')
.remove()
.end();
// Parse data and append new select options
//(omitted here; e.g. $('#byCollege').append($("<option>").attr(...))
},
error: function(data, status, er) {
alert("error: " + data + " status: " + status + " er:" + er);
}
});
});
});

Pass radio buttons with the same name to servlet

I have a form with a button that will dynamically add a group of inputs of the same form.
I already managed to get it done, except for one issue.
I couldn't pass the parameters from radio input type with the same name to the servlet for everytime I add the fields. It only passed the value to servlet once. Weird thing is I could pass the text input type successfully.
Or is there any other way to pass the value from the radio button to the servlet?
Here's the code:
<script type="text/javascript">
$(document).ready(function(){
var counter = 2;
$("#addDynamicDivs").click(function () {
var newTextBoxDiv1 = $(document.createElement('div'))
.attr("id", 'TextBoxDiv1');
newTextBoxDiv1.attr("style",'float: left;');
var newTextBoxDiv2 = $(document.createElement('div'))
.attr("id", 'TextBoxDiv2');
newTextBoxDiv2.attr("style",'float: left;');
var newTextBoxDiv3 = $(document.createElement('div'))
.attr("id", 'TextBoxDiv3');
newTextBoxDiv3.attr("style",'float: left;');
var newTextBoxDiv4 = $(document.createElement('div'))
.attr("id", 'TextBoxDiv4');
newTextBoxDiv4.attr("style",'float: left;');
newTextBoxDiv1.after().html('<label>Speaker Name : </label>' +
'<input type="text" name="speakername" id="speakername" value="" >');
newTextBoxDiv2.after().html('<label>Speaker Country : </label>' +
'<input type="text" name="speakercountry" id="speakercountry" value="" >');
newTextBoxDiv3.after().html('<label>Speaker Company : </label>' +
'<input type="text" name="speakercompany" id="speakercompany" value="" >');
newTextBoxDiv4.after().html('<label>ID Type: </label>' +
'<ul name="idtype class="forms-list">'+
'<li><input type="radio" name="idtype" id="idtype" value="New ID">'+
'<label for="New ID">New ID</label></li>'+
'<li><input type="radio" name="idtype" id="idtype" value="Old ID">'+
'<label for="Old ID">Old ID</label></li></ul>');
newTextBoxDiv1.appendTo("#TextBoxesGroup");
newTextBoxDiv2.appendTo("#TextBoxesGroup");
newTextBoxDiv3.appendTo("#TextBoxesGroup");
newTextBoxDiv4.appendTo("#TextBoxesGroup");
});
});
From the servlet, the parameters are retrieved by this code:
String[] speakername = request.getParameterValues("speakername");
String[] speakercountry = request.getParameterValues("speakercountry");
String[] speakercompany = request.getParameterValues("speakercompany");
String[] idtype = request.getParameterValues("idtype");
I print out the length of each String array above, and I got 2 for each of the parameters except for idtype which the length is 1.
All the dynamic params are already included inside the form.
Radio buttons will usually only send one value out of the group with the request. By design, only one radio button can be selected out of the group. If you add more radio buttons with the same name to the form, the browser should still pass only one selected value for the group when you submit the form.
If you want to have multiple of this form passed, you will be best off differentiating between the dynamically added forms (it looks like you want all the data to be sent together, so you'll need to add a unique identifier to the name of each <input> element, but otherwise having them in separate <form>s would be preferable). I would not recommend relying on the browser passing multiple <input>s with the same name in the same <form>.

liferay portlet can't get input field value

I can't figure out why i can't get an input value from a jsp. I'm using for cycle to make several input fiels for "choices", but when i'm trying to get values from a mvcportlet, it get nothing.
<aui:form action="<%=addPollURL%>">
<aui:fieldset>
<%
int optionCount = Integer.parseInt(optionCountS);
for (int i = 0; i < optionCount; i++) {
%>
<aui:input label="<%=Integer.toString(i + 1)%>" name="choice<%=i%>"
type="text" />
<%
}
%>
<aui:button-row>
<aui:button value="Add poll" type="submit" />
</aui:button-row>
</aui:fieldset>
</aui:form>
Here goes mvcportlet method
List<String> choices = new ArrayList<String>();
int count = Integer.parseInt(actualChoiceCount);
for (int i = 0; i < count; i++) {
System.err
.println("another choice"
+ ParamUtil
.getString(
actionRequest,
("choice" + i)));
choices.add(new String(ParamUtil.getString(actionRequest,
("choice" + i))));
}
Its really weird... but some ideas or tests
Is AddPollUrl an Action URL with named action and so your action is executed in your generic portlet?
Are you sure text fields are populated with values in the UI (there is no no explicit value in tag)? ParamUtil output would be the same without value that with a blank value
Try without type=text and write it as a single line (input tags)
Try aui:submit instead of aui:button type submit
Try adding an id to form or fields (Ive seen some problems with repeated forms if they dont have namespace)
Why new String(ParamUtil...)?
the most important... whats the output of your System.outs?
That happens because your input field has no value. Or at least it seems so.
You should modify the input to have the value parameter set to "choiceX" like:
<aui:input label="<%=Integer.toString(i + 1)%>" name="choice<%=i%>"
type="text" value="choice<%=i%>" />
Then you'll find it in actionRequest, like Jonny said:
request.getParameter("choice"+i);
This will return you the value of the input field, searching by it's name. So you can have your choice in the processAction method.
Regards !
Try using:
actionRequest.getParameter("choice" + i);
That's not the standard way of getting POST params from the request.

Categories

Resources