Grails - Select box tied to object ID and remote field - ajax

Run into a bit of an odd problem that is increasingly frustrating
Scenario: I have a list of domain objects, each has a g:select attached to it that is rendered by a remote field.
How do I tie the status variable OR the personInstance ID to the selection box, so that when I use the renderField, I update testDiv_(number)
View:
<g:each in="${listOfPeople}" status="i" var="personInstance">
<td>
Text: <g:remoteField action="getResults" controller="person" id="" update="testDiv_${personInstance.id}" paramName="search" name="getResults" value="" />
<g:each in ="${personInstance?.choices}" var="choice" status="x">
<li>${choice}</li>
</g:each>
</td>
<td>
<g:render template="renderThisTemplate"></g:render>
</td>
</g:each>
Template:
<div id="testDiv_${personInstance.id}" class="testDiv_${personInstance.id}">
<g:select id="aChoice" name="aChoice.id" from="${allChoices}" optionKey="id" value="" />
<g:actionSubmit action="addChoice" value="Add"/>
</div>
Edit
I know that the remote call (ajax) is passing the update for testDiv_(number). The problem is with the template ID and assigning that value to the template div.

Just incase anyone needs this answer in the future. Apparently you cannot reference the instance variable (personInstance) in the g:each from the template.
So I replaced the g:render with its code and it worked:
<g:each in="${listOfPeople}" status="i" var="personInstance">
<td>
Text: <g:remoteField action="getResults" controller="person" id="" update="testDiv_${personInstance.id}" paramName="search" name="getResults" value="" />
<g:each in ="${personInstance?.choices}" var="choice" status="x">
<li>${choice}</li>
</g:each>
</td>
<td>
<div id="testDiv_${personInstance.id}" class="testDiv_${personInstance.id}">
<g:select id="aChoice" name="aChoice.id" from="${allChoices}" optionKey="id" value="" />
<g:actionSubmit action="addChoice" value="Add"/>
</div>
</td>
</g:each>

Related

Alter multiple columns in the Database based on selected values- Hibernate

I am displaying the details of a particular table in my JSP page using a for-each loop in the following manner:
<c:forEach items="${List2}" var="alist">
<tr>
<td>
<input type="checkbox" name="check" value="${alist.check}">
</td>
<td>${alist.two}</td>
<td>${alist.three}</td>
<td>${alist.four}</td>
</tr>
</c:forEach>
<input type="radio" id="agree" value="Agree"/>Agree
<input type="radio" id="disagree" value="Disagree"/> Disagree
<input type="submit" value="Submit"/>
Now, there is no column named "check" in my DB. It is a transient field in my POJO. I do have a Agree/Disagree column in my DB. I want to check particular rows, click "Agree" or "Disagree" and on clicking Submit, the Agree/Disagree column for those records should be updated respectively. I'm using Spring MVC with Hibernate. Please tell me if any more info is required from my side.
You can do this with simple jQuery, Set class(say .chkbox here) to all checkboxes. Whenever any change event happened say,
if checked, the value of checkbox added to JS array.
If unchecked, the value will be removed from JS array.
$(document).ready(function() {
var selectedArray = [];
$('.chkbox').change(function() {
if($(this).is(":checked")) {
selectedArray.push($(this).val());
} else {
selectedArray.pop($(this).val());
}
//alert(selectedArray);
$("#textbox1").val(selectedArray);
});
});
Finally I used textbox to hold all the selected checkboxes value. You can make it into a hidden give a name attribute.
<input type="checkbox" class="chkbox" value="101"> This is 101<br />
<input type="checkbox" class="chkbox" value="102"> This is 102<br />
<input type="checkbox" class="chkbox" value="103"> This is 103<br />
<input type="checkbox" class="chkbox" value="110"> This is 110<br />
<input type="checkbox" class="chkbox" value="111"> This is 111<br />
<input type="checkbox" class="chkbox" value="112"> This is 112
<br />
<input type="hidden" id="textbox1" name="selectedArray" />
Sent it to a controller and split the values by comma (,).
Update :
In your code, you can update like this.
<c:forEach items="${List2}" var="alist">
<tr>
<td>
<input type="checkbox" class="chkbox" name="check" value="${alist.check}">
</td>
<td>${alist.two}</td>
<td>${alist.three}</td>
<td>${alist.four}</td>
</tr>
<input type="hidden" id="textbox1" name="selectedArray" />
</c:forEach>
That's all about required.
See the JS Demo how it works. Hope this helps.

JSF change how f:selectItem renders

I have a tag h:selectManyCheckbox, in it a loop over a list. for each item in the list I need a checkbox. Unfortunately the format of the checkbox + label does not correspond to the table which jsf creates. I need a div around each item, like this:
<div class="form_control var_checkbox">custom
<input type="checkbox" class="checkbox" name="service" id="service_0" data-product="additional_price" data-product-add-price="100.0">
<label class="label" for="service_0">title</label>
<span class="guarantee_price">CHF 100.0</span>
</div>
but jsf renders it like this:
<table>
<tbody>
<tr>
<td><input id="addToCart:j_id_29_2:0" type="checkbox" name="addToCart:j_id_29_2" value="0"><label for="addToCart:j_id_29_2:0"> title</label></td>
<td><input id="addToCart:j_id_29_2:1" type="checkbox" name="addToCart:j_id_29_2" value="1"><label for="addToCart:j_id_29_2:1"> titel2</label></td>
</tr>
</tbody>
</table>
here's the code currently generating it:
<h:selectManyCheckbox value="${addToCartBean.selectedServicesIndexes}">
<c:forEach items="#{productServicesJSFBean.productServicePlusBeanKeySet}" var="productServicePlusKey">
<c:forEach items="#{productServicesJSFBean.productServicePlusBeans[productServicePlusKey]}" var="productServicePlus">
<div class="form_control var_checkbox">
<f:selectItem itemValue="${counter}" itemLabel="${productServicePlus.servicePlusDisplay.title}" >custom </f:selectItem>
</div>
<c:set var="counter" value="${counter + 1}"/>
</c:forEach>
</c:forEach>
</h:selectManyCheckbox>
I tried creating the checkbox by hand, but jsf doesnt pick it up. We can not use a table, it has to be in the div format. How can I change how jsf renders those selectItems. I dont want it globally, only for those here. How can I do that?
someone I sent this question to sent me this SO question, which I didnt find through google: Render selectManyCheckbox without HTML table . got it working with <h:outputLabel><h:selectBooleanCheckbox>

GRAILS Placement of g:form affects params passed to controller

I have a HTML table that has a form field that can be updated for each row. In each row, I have created a form and when you change the editable field, a button will appear and you can save the change. This happens remotely using the GRAILS g:submitToRemote tag.
I have some hidden fields that also need to be passed.
When I do the following, none of the fields (the 3 hidden ones, nor the single visible ones) are passed the controller:
<g:form action="updatebaseprice" id="${obj.id}" name="form_${obj.id}">
<tr>
<td>${prod.product.name}</td>
<td class="text-center">${prod.product.type}</td>
<td class="text-center"><g:formatNumber number="${prod.product.unitCost}" type="currency" currencyCode="USD" /></td>
<td class="text-center">
<div class="row collapse">
<div class="small-3 columns">
<span class="prefix radius">$</span>
</div>
<div class="small-9 columns">
<g:field type="text" class="bemt_small_input_field" value="${prod.basePrice}" id="basePrice_${prod.id}" name="basePrice" onchange="Project.updateBasePrice(${prod.id});" maxlength="6"/>
</div>
</div>
</td>
<td class="text-center"><span id="display_recoveryPercent_${prod.id}"><g:formatNumber number="${prod.recoveryPercent}" type="number" minFractionDigits="2" maxFractionDigits="2"/></span>%</td>
<td class="text-center">
<g:hiddenField name="projectProduct" value="${prod.id}"></g:hiddenField>
<g:hiddenField name="unitCost" id="unitCost_${prod.id}" value="${prod.product.unitCost}"></g:hiddenField>
<g:hiddenField name="recoveryPercent" id="recoveryPercent_${prod.id}" value="${prod.recoveryPercent}"></g:hiddenField>
<g:submitToRemote id="save_button_${prod.id}" class="hidden button alert save_unitprice radius" id="save_button_${prod.id}" url="[action: 'updatebaseprice']" onSuccess="Project.saveBasePrice();" value="Save"/>
</td>
</tr></g:form>
Using a println params in the controller, nothing in printed.
When I do the following:
<tr>
<td>${prod.product.name}</td>
<td class="text-center">${prod.product.type}</td>
<td class="text-center"><g:formatNumber number="${prod.product.unitCost}" type="currency" currencyCode="USD" /></td>
<td class="text-center">
<div class="row collapse">
<div class="small-3 columns">
<span class="prefix radius">$</span>
</div>
<div class="small-9 columns">
<g:field type="text" class="bemt_small_input_field" value="${prod.basePrice}" id="basePrice_${prod.id}" name="basePrice" onchange="Project.updateBasePrice(${prod.id});" maxlength="6"/>
</div>
</div>
</td>
<td class="text-center"><span id="display_recoveryPercent_${prod.id}"><g:formatNumber number="${prod.recoveryPercent}" type="number" minFractionDigits="2" maxFractionDigits="2"/></span>%</td>
<td class="text-center">
<g:form action="updatebaseprice" id="${obj.id}" name="form_${obj.id}">
<g:hiddenField name="projectProduct" value="${prod.id}"></g:hiddenField>
<g:hiddenField name="unitCost" id="unitCost_${prod.id}" value="${prod.product.unitCost}"></g:hiddenField>
<g:hiddenField name="recoveryPercent" id="recoveryPercent_${prod.id}" value="${prod.recoveryPercent}"></g:hiddenField>
<g:submitToRemote id="save_button_${prod.id}" class="hidden button alert save_unitprice radius" id="save_button_${prod.id}" url="[action: 'updatebaseprice']" onSuccess="Project.saveBasePrice();" value="Save"/>
</g:form>
</td>
I get the three hidden params (as excepted), but not the input that is above the form (I don't expect that, given it is outside the form). The question I have is, why is the first way not returning anything, when I expect it to return the three hidden and one visible field values as params?
Thanks
The problem is that you're trying to nest a form inside the html table structure.
As you figured out, you can have a form inside a single table cell but trying to put a table row inside a form won't work.
See this question for some more info: Form inside a table

Dynamically added input elements are not preserving entered data when creating new input elements

I've created a test app to learn more about asp.net mvc. The app is supposed to allow the use to add an "unlimited" number of inputs via jQuery using partial views and editor templates. I've managed to get the adding of the new input elements but I'm having issues preserving the entered data from the user when adding newer input elements.
My strongly-typed view
#model TestApp.Models.ItemViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.ItemName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemName)
#Html.ValidationMessageFor(model => model.ItemName)
</div>
<div class="editor-label">
Click to add rates
</div>
<div class="editor-field">
Add Rate
<input type="hidden" value="0" id="rateCounter" />
</div>
<br />
<span id="itemRates"></span>
<p>
<input type="submit" value="Save" />
</p>
}
My javascript
When the user clicks on the NewRate element above, I fire this jQuery to get the partial view. I also keep track of the number of rows created by the user via a hidden element rateCounter which I increment everytime the click event fires.
$("#NewRate").click(function () {
var count = parseInt($("#rateCounter").val());
$("#rateCounter").val(count + 1);
$.ajax({
type: 'GET',
url: '/Item/AddRate',
data: {
rateCount: $("#rateCounter").val()
},
success: function (data) {
$('#itemRates').html(data);
}
});
});
My controller
This accepts the number of rows to create and passes to the partial view.
public PartialViewResult AddRate(int rateCount)
{
var itemVM = new ItemViewModel { Rates = new List<ItemRatesViewModel>() };
for (int i = 0; i < RateCount; i++)
{
itemVM.Rates.Add(new ItemRatesViewModel());
}
return PartialView("_ItemRates", itemVM);
}
My strongly-typed partial view
The partial view just uses an editor template
#model TestApp.Models.ItemViewModel
#Html.EditorFor(model => model.Rates)
My editor template
The editor template basically displays each rate
#model TestApp.Models.ItemRatesViewModel
<tr>
<td>
#Html.EditorFor(model => model.Rate)
#Html.ValidationMessageFor(model => model.Rate)
</td>
<td>
#Html.EditorFor(model => model.StartDate)
#Html.ValidationMessageFor(model => model.StartDate)
</td>
<td>
#Html.EditorFor(model => model.EndDate)
#Html.ValidationMessageFor(model => model.EndDate)
</td>
</tr>
On the first click
Using Google Chrome's developer tools, I see that the response is like this. Which should be correct. When I submit the form, the model binder picks up the entered data.
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_0__Rate" name="Rates[0].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[0].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[0].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
On the second click
The entered data on the first set of input element (index [0]) is discarded and replaced by newly initialized one since I am using $('#itemRates').html(data); in my javascript instead of $('#itemRates').append(data);. Below is what I get. When I submit the form, the model binder picks up the entered data correctly in the Rates collection of the view model.
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_0__Rate" name="Rates[0].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[0].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[0].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_1__Rate" name="Rates[1].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[1].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[1].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
FINALLY, my question
Is there a way to get just the 2nd row (index [1]) in the generated response then use jQuery's append instead of replacing the whole html with the new rows? What is the correct way of doing this? I know I'm close but a little guidance would go a long way. :)
I probably wouldn't be going back to the server and getting the whole view with all the rows this way.
The way MVC parses the sent data once posting the form is the array of elements sent back (specified by the number in [] brackets in the name attribute of the elements.
The way I have done it in the past is cloned the row by jquery and used a regex function to replace the[0] with [1] and cleared the values out also. Then just append it.
This will also save you from doing a call to the server every time the add is clicked.

how to get xpath preceding-sibling working for this table

I have a table where I need to find if the checkbox corresponding to a cell is checked or not, see for example, I need to find out if the checkbox id=830 which is a sibling of DeviceHelp is checked or not.
Similarly for element Contact, I will have to check whether checkbox id="72" is checked / unchecked
And I can only rely on the text elements (contact, DeviceHelp, etc) to get the checkboxes state and not the checkbox ids which could change.
<tr class="row active" style="display: table-row;">
<td>
<input id="72" class="rowcheck" type="checkbox" value="true" name="ModesForUi[0].Allow" categoryid="58" disabled="">
<input type="hidden" value="false" name="ModesForUi[0].Allow">
</td>
<td> Administration - Read </td>
<td>
Contact
<input id="ModesForUi_0__ResourceID" type="hidden" value="72" name="ModesForUi[0].ResourceID">
<input id="ModesForUi_0__ModeID" type="hidden" value="12185" name="ModesForUi[0].ModeID">
</td>
<td> Controls access to Search Contacts link and to view contact details page. Navigate to Menu\Advanced\More </td>
</tr>
<tr class="row active" style="display: table-row;">
<td>
<input id="830" class="rowcheck" type="checkbox" value="true" name="ModesForUi[1].Allow" categoryid="58" disabled="">
<input type="hidden" value="false" name="ModesForUi[1].Allow">
</td>
<td> Administration - Read </td>
<td>
DeviceHelp
<input id="ModesForUi_1__ResourceID" type="hidden" value="830" name="ModesForUi[1].ResourceID">
<input id="ModesForUi_1__ModeID" type="hidden" value="12186" name="ModesForUi[1].ModeID">
</td>
<td> Controls access to Help icon displayed next to logout icon and next to the menu. </td>
</tr>
Have tried the following, but I am not getting the checkbox value
"ancestor::td[1]/input[1]/preceding-sibling::td[normalize-space(text())='DeviceHelp']")
And
//tr[position()>1]/td[normalize-space(text())='DeviceHelp*']/parent::td/preceding-sibling::td/input#value
Please xpath experts could you shine some light on what is wrong with the paths above and how to get to the checkbox ?
Thanks!
I think I know what you're trying to get here...
Try this for Device Help:
/root/tr/td[normalize-space(text())='DeviceHelp']/../td[1]/input[1]/#value
And this for Contact:
/root/tr/td[normalize-space(text())='Contact']/../td[1]/input[1]/#value
"root" is just whatever node you're starting from, I added that to test locally, as the XML snippet isn't complete.
EDIT
Try this:
//tr/td[normalize-space(text())='DeviceHelp']/../td[1]/input[1]/#value
//tr/td[normalize-space(text())='Contact']/../td[1]/input[1]/#value

Resources