I have a GSP containing some rows with an checkbox which lets the user select several rows.
<table>
<thead>
<tr>
// Column headers
</tr>
</thead>
<tbody>
<g:each in="${itemList}" status="i"
var="instance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
// Some other rows
<td>
<g:checkBox name="selected"
value="${instance.id}"
checked="false" />
</td>
</tr>
</g:each>
</tbody>
And a pagination under my table:
<div class="pagination">
<g:paginate total="${total}" params="${params}"/>
</div>
Now the problem is when I switch from Page 1 -> Page 2 -> and then back to Page 1 all the checkboxes from Page 1 are reseted.
As pagination calls the list controller method I checked the following on page switch by Watching the following in Debugger when list controller method gets called:
params.list('selected')
But unfortunately the list is empty.
Pagination does not submit a form (or at least not like you're thinking it does; I really don't remember if the underlying logic uses a form or not) so your checkboxes are not being submitted to anywhere.
You need to consider different approaches for having your form submitted so that your checkbox selections are persisted. Two approaches could be:
Write your own pagination tag that wraps g.paginate and modifies which params are sent so that your checkbox values are included.
Add ajax handling to your checkboxes so that they are submitted immediately when changed.
Related
I have a simple table and I have checkbox inside that table. If checkbox is selected I want to display other features.
My code:
<table>
<tr th:each="obj,iterationStatus : ${objs}">
<td th:text="${obj.name}"></td>
<td><input type="checkbox" name="firstcheckbox"></td>
<td th:if="isChecked">
<!-- do something -->
</td>
</tr>
</table>
How I do this without using javascript and backbean?
In this case you have two options, the first option you don't want but is not a bad option is using Javascript: creating a function called isChecked.
Otherwise, you can know if a checkbox is checked with thymeleaf in the case you are in a form which calls itself. You could do something like if(firstcheckbox != null) and, of course, your checkbox would have a value <input type="checkbox" name="firstcheckbox" value="value">. Finally, you must add as attribute in your model: model.addAttribute("firstCheckbox", firstCheckbox);
Im running into an issue, and I think the issue is with how my page.all is pulling radio button questions in.
So here is the HTML for the table itself (Multiple questions with 5 radio button choices a piece):
<table class="table table-striped table-stuff table-collapsible">
<colgroup>
<thead>
<tbody>
<input id="0_answer_question_id" value="9966" name="response[answers][0][answer_id]" type="hidden">
<tr>
<td class="heading">
<td class="option">
<div class="radio-inline radio-inline--empty">
<input id="question_1_1" value="1" name="response[answers_attributes][0][answer_opinion]" type="radio">
<label for="question_1_1">Strongly Disagree</label>
</div>
</td>
<td class="option">
<td class="option">
<td class="option">
<td class="option">
</tr>
<input id="response_1_question_id" value="9966" name="response[answers_attributes][1][answer_question_id]" type="hidden">
<tr>
<input id="response_1_id" value="<a number>" name="response[answers_attributes][1][id]" type="hidden">
<Same as above repeated 5 times with numbers changed>
</tbody>
</table>
Im using:
page.all('table.table-stuff tbody tr', minimum: 6).each do |row|
row.all("td label").sample.trigger('click')
end
To get each row and select one from it. HOWEVER, I notice "sometimes" a row will not have one selected. My theory is the "heading" (which has a <label> itself is accepting one of the clicks perhaps? (since from my understanding of how page.all works it's grabbing every tbody tr within the table...but is maybe grabbing the heading too? (since it contains a td label?)
Also when a table is named something like table table-striped table-stuff table-collapsible...how can you tell what the actual table "name" is? (I didn't write this website, just doing tests for it). When putting it in the page.all('table.<etc>')?
If the heading td (it's not expanded in your example) also contains a label element (so it would be included in the results of your all call) then you just need to change the CSS selector so it wouldn't be included - something like
row.all("td.option label").sample.trigger('click') # only choose labels contined in tds with the class of 'option'
or
row.all("td:not(.heading) label").sample.trigger('click') # choose labels contained in tds without the class of 'heading'
On your second question about table names, I don't really understand what you're asking. Tables don't have name attributes, they could have an id attribute or a caption containing some text which could then be used to find them with capybara via find(:table, 'id or caption text') or within_table('id or caption text') { code to execute within scope of the table }. Rather, you seem to be talking about the classes on the element which are specified in a CSS selector with '.'. Therefore a CSS selector to match a table element with all the classes you listed would be - 'table.table.table-striped.table-stuff.table-collapsible'
Note: If you're sure there's always only 5 choices you could add the :count option to your find to make sure your selector is only finding those items
row.all("td.option label", count: 5).sample.trigger('click')
I have an MVC5/Bootstrap application that has a page where the user, as part of a larger form, can add and delete rows in a table.
To add rows, the user clicks an icon and then searches for data using a TypeAhead field that appears in a popover, which when selected retrieves row data using AJAX and inserts the row into the table.
Rows can be deleted by clicking on an icon in each row, the row is then removed. Both these actions affect a bound hidden input field that contains a list of IDs of the rows, e.g. "{100001},{100003},{100004}".
When the form that contains this table is submitted this hidden field is parsed and the appropriate database actions are performed using EF6 to add or delete items.
My question is whether this approach of using a single hidden field that is manually parsed by the controller method is the best choice. I was thinking there may be a more idiomatic way to utilize MVC model binding. e.g. having hidden checkboxes on each row or some such mechanism.
The ViewModel you are binding to could contain a collection of row viewmodels that wrap all inputs for a single row.
To submit these, bind them using the index.
<table>
<tbody>
<tr>
<td>
#Html.HiddenFor(m => m.RowData[0].SomeRowProperty)
<input type="hidden" name="RowData.Index" value="0" />
</td>
</tr>
<tr>
<td>
#Html.HiddenFor(m => m.RowData[1].SomeRowProperty)
<input type="hidden" name="RowData.Index" value="1" />
</td>
</tr>
</tbody>
</table>
See also Model binding to a list
I have a list of table names in a request attribute, "BillSummaryTables". I am iterating through the list and I want to use each table name to get a request attribute for that particular table name. Corresponding to each table name I have another list in request attribute and I want to iterate through that.
This is what I am doing.
<s:iterator value='#request.BillSummaryTables' var="tableName" status="itStatus">
<div class="contentbox" role="content">
<table class="rpt">
<s:iterator value="#request.get('%{#tableName}').getData()" var="ocRow" status="itStatus">
<tr style="border:1px solid #CCCCCC">
<s:iterator value='#ocRow' var="cell" status="itStatus2">
<td>
<s:property value="#cell.getValue()"/>
</td>
</s:iterator>
</tr>
</s:iterator>
<tr>
<s:iterator value="#request.get('%{#tableName}').getData()" var="ocTotal">
<td>
<s:property value="#ocTotal"/>
</td>
</s:iterator>
</tr>
</table>
</div>
</s:iterator>
I have also tried
#request[<s:property value="#tableName" />].getData()
and
#request['<s:property value="#tableName" />'].getData()
and
#request.%{#tableName}
But nothing is returned in any case.
However, this code works fine if I hard code the values.
i.e. if i use: #request['other_charges'].getData()
Note: I am able to retrieve the list of tableName (#request.BillSummaryTables).
#1) You are using three nested iterators, but both the first and the second have an instance of IteratorStatus called itStatus; they must have different names to work.
#2) If the Lists corresponding to the Table name is, effectively, a List, then you should iterate the list, not the getData() stuff (what is that ?)
#3) Why using request ? why not simply using an HashMap on the Action (with the getter), adding elements dynamically using table names as key ?
#4) This #request[<s:property value="#tableName" />].getData() will obviously not work if put inside another Struts2 tag, like an Iterator (cannot nest Struts2 tags).
However, try something like this (I stripped the second iterator, make it running before, then add stuff), and see if it works (and what it prints):
<s:iterator value='#request.BillSummaryTables' var="tableName" status="statusAllTables">
<div class="contentbox" role="content">
<br/>==== START DEBUG ====
<br/>Current table name: [<s:property value="#tableName"/>]
<br/>Corresponding request object: [<s:property value="#request['%{#tableName}']"/>]
<br/>getData on that object: [<s:property value="#request['%{#tableName}'].getData()"/>]
<br/>===== END DEBUG =====
<table class="rpt">
<s:iterator value="#request['%{#tableName}'].getData()" var="ocRow" status="statusThisTable">
<tr style="border:1px solid #CCCCCC">
<s:iterator value='#ocRow' var="cell" status="statusThisField">
<td>
<s:property value="#cell.getValue()"/>
</td>
</s:iterator>
</tr>
</s:iterator>
</table>
</div>
</s:iterator>
EDIT
Ok, but then why are you using request.setAttribute ? Actions are created per-request... just use a private List<MyObjects> myObjects with its getter (public List<MyObject> getMyObjects()), and call it from JSP with <s:iterator value="myObjects"> (in your case, <s:iterator value="myObjects.data">.
Please note that .getData() in OGNL should become .data (i didn't noticed it before), removing the get, lowering the first letter of the method, and removing round brackets...
Retry and let us know.
I need to update the value of a textField, using a value on the server, based on the value the user chooses in a g:select. In code:
<g:select name="description" from="${momentum.MoneyTransType.prodList}" value="${moneyInstance?.description}"
noSelection="['':'-Select Description-']" onChange="${remoteFunction(action:'setHowMuch', update:[success:'howMuch', failure:'failure'],
params:'\'selection=\' + this.value', options=[asynchronous:false])}"/>
<g:textField id="howMuch" name="howMuch" value="${moneyInstance?.howMuch}"/>
It's not working. If I give the "update:[success:" a div id, all is good, but that's not what I want. I need to allow the user to enter in a free flow description (which I'll have in another textfield), and a free flow amount. I guess I could hide a div and then listen for changes to that div via jQuery, and then update the amount textField. Should I be able to update a textField using the remoteFunction "update" capability or using another grails capability?
Strangely, putting in a temporary 'toHide' div with a jQuery change function isn't working to update the textField, i.e. the following alert, etc, isn't firing:
$('#toHide').change(function() {
alert(" I got changed, value:");
$("#howMuch").text($(this).val());
});
Well, after writing all the below, I reread your question and see you stated you know it works with a div. So the rest of my answer might not be helpful, but what's wrong with using a div? An empty div won't display anything, so you don't need to hide it. So FWIW:
Put your <g:textField ...> in a template.
Add a div where where you want the template to be rendered. In other
words, replace the current <g:textField ..> with <div id=updateme name=updateme></div>
In your setHowMuch action, render the template.
For example, I do:
In view:
<g:select class='setTagtypeValue-class'
name='tagtype-${i}-header'
from="${org.maflt.ibidem.Tagtype.list(sort:'tagtype').groupBy{it.tagtype}.keySet()}"
value="${setTagtypeValue?.tagtype?.tagtype}"
valueMessagePrefix="tagtype"
noSelection="${['null':'Select One...']}"
onchange="${remoteFunction(action:'options', update:'tagtype-options-${i}',
params:'\'tagtype=\' + this.value +\'&i=${i}\'' )}" />
Controller action:
def options = {
def i = params.i ?: 0
def tagtypes = Tagtype.findAllByTagtype(params.tagtype)
render(template:"tagtypeList", model:[tagtypes:tagtypes,i:i])
}
tagypeList Template:
<table>
<tr>
<th></th>
<th><g:message code="tagtype.lookup"
default="Lookup Table" /></th>
<th><g:message code="tagtype.regexpression"
default="Field Rule" /></th>
<th><g:message code="tagtype.uicomponent"
default="UI Component" /></th>
</tr>
<g:each in="${tagtypes}" var="tagtype" status="j">
<tr>
<td><g:radio name="setTagtypesList[${i}].tagtype.id" value="${tagtype.id}"
checked="${(setTagtypeValue?.tagtype?.id == tagtype.id ||
(!setTagtypeValue?.tagtype?.id && j==0))}"></g:radio></td>
<td>${tagtype.lookupTable}</td>
<td>${tagtype.regexpression}</td>
<td><g:message code="${'uicomponent.' + tagtype.uicomponent.id}"
default="${tagtype.uicomponent.uicomponent}" />
</td>
</tr>
</g:each>
</table>
This code is from the metadataset (called field set in the UI) screen in http://www.maflt.org/products/Ibidem.