Grails passing property with dot to controller - sorting

I am trying to pass params.sort to my controller.
if (params.sort && params.order == "asc") {
pricesInPriceList = row.prices.sort{it.material."${params.sort}"}
}
if (params.sort && params.order == "desc"){
pricesInPriceList = row.prices.sort{it.material."${params.sort}"}.reverse()
}
[priceListInstance: row, pricesInPriceList: pricesInPriceList]
It works fine with following gsp:
<tr>
<g:sortableColumn property="sku" title="SKU" />
<g:sortableColumn property="description" title="Description" />
</tr>
Now if I change my gsp to following:
<tr>
<g:sortableColumn property="material.sku" title="SKU" />
<g:sortableColumn property="material.description" title="Description" />
</tr>
and my controller part to:
if (params.sort && params.order == "asc") {
pricesInPriceList = row.prices.sort{it."${params.sort}"}
}
if (params.sort && params.order == "desc"){
pricesInPriceList = row.prices.sort{it."${params.sort}"}.reverse()
}
Why this is happening? now my params.sort has a value material.sku for example however if I want to evaluate it."${params.sort}" it does not work. But if I will change my params.sort to sku and then change my controller to it.material."${params.sort}" everything is working. Where I am making mistake?
Thank you.

This sort will work for both cases - params.sort = 'parent' or params.sort = 'parent.child'
row.prices.sort{ params.sort.tokenize('.').inject(it){v, k -> v."$k"} }
It's essentially the same as the solution for this question: Grails accessing nested fields using gstrings

from your modified gsp code :
<tr>
<g:sortableColumn property="material.sku" title="SKU" />
<g:sortableColumn property="material.description" title="Description" />
</tr>
one most possible reason why your code is not working is
1.property="material.sku" did not match the property of the field and i am sure you never
define the property name in that way. cause the
property - name of the property relating to the field
2.if you are trying to read property from message source, then you could do as follows
<tr>
<g:sortableColumn property="sku" title="SKU" titleKey="material.sku" />
<g:sortableColumn property="description" title="Description" titleKey="material.sku"/>
</tr>
Hope this may help you.
Regards
Motilal

Related

Encounter error when there is if else in mvc view

i am new in mvc and trying to learn.i want to display a form when ViewBag.Success is null or empty but if ViewBag.Success is true then i want to render a partial view.
here is my code
<div id="mydiv">
#if (ViewBag.Success != null && ViewBag.Success == true) //Show the message
{
Html.RenderPartial("Message");
}
else
{
#using (Html.BeginForm("Save", "Game", FormMethod.Post, new { #Id = "Form1" }))
{
<table border="0">
<tr>
<td>
Name :
</td>
<td>
<input name="name" type="text" />
</td>
</tr>
<tr>
<td>
Salary :
</td>
<td>
<input name="salary" type="text" />
</td>
</tr>
<tr>
<td colspan="2">
<input name="btnSubmit" type="submit" value="Save" />
</td>
</tr>
</table>
}
}
</div>
the error message i am getting when i am running like
Expected a "{" but found a "/". Block statements must be enclosed in "{" and "}". You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
what i am doing wrong not being able to understand. please help & guide. thanks
# symbol is only required when your code is contained within an HTML element. The using statement does not need the # because it is a direct decedent of your if else block.
Example:
<div> <!-- html tag -->
#if(something == somethingElse) // requires # because direct decedent of html tag <div>
{
<p>
#for (var i=0; i < len; i++) // requires # because direct decedent of html tag <p>
{
if(i == 1) // doesnt require #, not decedent of any HTML tag, instead direct decedent of another razor statement (for)
{
//do something
}
}
</p>
}
</div>
The # sign is use to distinguish between a simple string / HTML and razor statements. You only need that when you are writing C# code between HTML code. But when you are have started a C# code block, the ASP.NET MVC View Engine is intelligent enough to understand that the code that follows is C# and not simply some string.

How to send back the model data from jsp to controller

I have a controller which sets few values to a model and sends to jsp. In jsp i need to show those values(as labels) along with additional values from user as input values. When i submit the jsp i only get valid values that user has entered and the values set earlier by controller is null.
JSP
<form:form
action="${pageContext.request.contextPath}/admin/deviceAction.html"
modelAttribute="deviceData">
<table class="gridtable" width="500px">
<tr>
<td>Device Name : </td>
<td>${deviceData.deviceName}</td>
</tr>
<tr>
<td>Model Name : </td>
<td>${deviceData.modelName}</td>
</tr>
<tr>
<td>Serial No : </td>
<td>${deviceData.serialNo}</td>
</tr>
<tr>
<td>Device Id : </td>
<td>${deviceData.deviceId}</td>
</tr>
<tr>
<td>Status : </td>
<td>${deviceData.statusCode}</td>
</tr>
<tr>
<td>Action : <span class="required">*</span></td>
<td>
<form:select path="deviceAction" >
<form:option value="" label="--- Select ---" />
<form:options items="${model.actionList}" />
</form:select>
</td>
</tr>
</table>
<input type="submit" value="Submit" id="btn_submit">
</form:form>
Controller:
public ModelAndView beforeSubmit() {
ModelAndView modelView = new ModelAndView();
DeviceData deviceData = new DeviceData();
deviceData.setDevicePk("123");
deviceData.setAccessToken("abcwetrwertewrtetr");
deviceData.setDeviceId("deferterterterterwtetetertg");
deviceData.setDeviceName("test");
deviceData.setEnrolledDate("7-8-13");
deviceData.setModelName("test1");
deviceData.setSerialNo("test2dsfgdfgdfg");
deviceData.setStatusCode("test3");
List<String> actionList = getActionList();
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("actionList", actionList);
modelView.addObject("deviceData", deviceData);
modelView.addObject("model", model);
modelView.setViewName("admin/tokenSearchResult");
}
public ModelAndView afterSubmit() {
#ModelAttribute("deviceData") DeviceData deviceData, BindingResult result) {
logger.info("#################device datas are : " + deviceData.getDevicePk() + "###### " + deviceData.getDeviceAction());
return new ModelAndView();
}
deviceData.getDevicePk() is null
Only the drop down value is having valid value. Other values displayed in the screen are received as null.
Edit:
Till now i have found only one solution:
<form:input path="deviceName" readonly="true" />
But this way UI does not looks good. The editable and non editable values mixup in the screen. Looking for a better answer
Finally i am using hidden parameters to solve the problem.
Example:
<td>${deviceData.deviceName}</td>
is replaced by:
<td><form:hidden path="deviceName"</td>
By this way it helps me to avoid any css work(which i am not much comfortable)
If anyone get a better solution kindly post it here
You need to make them into form inputs using the Spring form tags in much the same way as you have for the form:select. If they are not editable by the user, you can always disable them.
You can simple hide those input. For example :
<input type="hidden" name="VehSeriesModelId" value="${vehDetailsVM.id }">
This way, you can get the data to the controller and the user will also not be able to edit the value. On the other hand, your form will also not show it :)

Can I access the same controller multiple times in one view without changing the view?

I am using Spring MVC. I have a view that dynamically populates 2 dropdown lists based on queries called from the controller. I want to dynamically run a query based on the first dropdown selection to change the second dropdown, which means access the controller again (I think). Can I access the controller multiple times from the same view without changing the view? So for example, say starting out the first dropdown was a list of US States and the second started out as a list of all US cities, if I selected NC from the first list I would want to change the second list to include only NC cities.
Here is an example of the first dropdown:
<select name = "states" onChange = "populateCityList(this.options[this.selectedIndex].value)">
<option value ="*">All States</option>
<c:forEach items="${states}" var ="state">
<option value ="${state}">${state}</option>
Pretty straightforward, but I don't really know where to go from there. I have it calling a Javascript function within the current view right now, but I don't know if that is correct or what to even do within that function.
The magic word is AJAX.
Your JavaScript function needs to make an AJAX request to your controller, which should ideally return a JSON data structure containing the values for the second drop down. Your JS function should then have a callback that catches the JSON from your controller and populates the drop down HTML by manipulating the DOM. JQuery is the way to go. There are lots of examples on the web, just search for it.
Hi #user2033734 you can do something like this:
JQuery code
$(document).ready(function() {
$("#id1").change(function () {
position = $(this).attr("name");
val = $(this).val()
if((position == 'id1') && (val == 0)) {
$("#id2").html('<option value="0" selected="selected">Select...</option>')
} else {
$("#id2").html('<option selected="selected" value="0">Loading...</option>')
var id = $("#id1").find(':selected').val()
$("#id2").load('controllerMethod?yourVariable=' + id, function(response, status, xhr) {
if(status == "error") {
alert("No can getting Data. \nPlease, Try to late");
}
})
}
})
})
And JSP within
<table style="width: 100%;">
<tr>
<td width="40%"><form:label path="">Data 1: </form:label></td>
<td width="60%">
<form:select path="" cssClass="" id="id1">
<form:option value="" label="Select..." />
<form:options items="${yourList1FromController}" itemValue="id1" itemLabel="nameLabel1" />
</form:select>
</td>
</tr>
<tr>
<td width="40%"><form:label path="">Data 2: </form:label></td>
<td width="60%">
<form:select path="" cssClass="" id="id2">
<form:option value="" label="Select..." />
<form:options items="${yourList2FromController}" itemValue="id2" itemLabel="nameLabel2" />
</form:select>
</td>
</tr>
</table>
I hope help you :)
One solution would be to move some of the data gathering out into a service, so your main controller could use the service to gather the data before sending to the view.

validation using ajax in struts2

I used ajax validation to validate the following
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblCustomBillNo" style="width: 15%" class="searchCriteriaCellLbl">
The custom Bill Number
</td>
<td width="5" class="searchCriteriaCellLbl">:</td>
<td class="searchCriteriaCellVal">
<s:textfield id="customBillNo" name="customBillNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="customBillNo" />
</td>
</tr>
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblBillNo" style="width: 15%" class="searchCriteriaCellLbl">
<s:property value="%{getText('billNo')}" />
</td>
<td width="5" class="searchCriteriaCellLbl">:
</td>
<td class="searchCriteriaCellVal">
<s:textfield label="billNo" id="billNo" name="billNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="billNo" />
</td>
</tr>
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblCarrierNo" style="width: 15%" class="searchCriteriaCellLbl">
The carrier Number
</td>
<td width="5" class="searchCriteriaCellLbl">:
</td>
<td class="searchCriteriaCellVal">
<s:textfield label="carrierNo" id="carrierNo" name="carrierNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="carrierNo" />
</td>
</tr>
I use the following internationalization for errors in golbal i18n file
errors.required=${getText(fieldName)} requireddd
and this validation file
<validators>
<field name="customBillNo">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message key="errors.required" />
</field-validator>
</field>
<field name="billNo">
<field-validator type="required" short-circuit="true">
<message key="errors.required" />
</field-validator>
</field>
<field name="carrierNo">
<field-validator type="required" short-circuit="true">
<message key="errors.required" />
</field-validator>
</field>
</validators>
and i put this javascript to use ajax validation
function validate(){
//document.all.loading.style.display = 'block';
var searchUrl = 'AddEnteringApproval_approval';
var params = '';
var elemArray = document.mainForm.elements;
for (var i = 0; i < elemArray.length;i++)
{
var element = elemArray[i];
var elementName= element.name;
if(elementName=='formAction')
continue;
params += '&' + elementName+'='+ encodeURIComponent(element.value);
}
params += '&struts.enableJSONValidation=true&struts.validateOnly=true';
createXmlHttpObject(); // this is my function that prepare ajax
sendRequestPost(http_request,searchUrl,false,params);
postValidation();
}
function postValidation() {
var form = $('#mainForm');
var text = http_request.responseText;
//clear previous validation errors, if any
StrutsUtils.clearValidationErrors(form);
alert(text)
//get errors from response
//var text = request.responseText;
var errorsObject = StrutsUtils.getValidationErrors(text);
//show errors, if any
if(errorsObject.fieldErrors)
{
StrutsUtils.showValidationErrors(form, errorsObject);
}
else
{
//good to go, regular submit
form.submit();
}
}
/* This is one of the functions that doesn't work using the simple theme, so I redefined it.
This can be changed to clear the previous errors, as it does in the commented example
cleaning the errors on divErrors.
As I am just showing the messages with alerts I don't need to clear anything,
but the method still need to be redefined, even if it is empty.
*/
StrutsUtils.clearValidationErrors = function(form, errors) {
//clear the div errors
//$('#divErrors').empty();
}
/* This method is responsible to show the messages.
The original versions works with the xhrml and css-xhtml theme but doesn't work with the simple theme
so I override the method with another implementation that shows the messages using alerts.
You can change the implementation to show the messages as you want,
but as the previous method this has to be redefined.
*/
StrutsUtils.showValidationErrors = function(form, errors) {
if(errors.fieldErrors)
{alert((errors.fieldErrors))
for(var fieldName in errors.fieldErrors)
{
alert("errors.fieldErrors[fieldName] " + errors.fieldErrors[fieldName]);
for(var i = 0; i < errors.fieldErrors[fieldName].length; i++)
{
alert('Field ->' + fieldName + '\nError -> ' + errors.fieldErrors[fieldName][i]);
}
}
}
};
but when i execute the code i get no organized JSON text i showed in alert message box, the field name is not like the one in the error message, the second field name is missing, the third field name is cut (i.e. carrierNo becomes rNo ).
can you help me. i want the field name in the JSON error match the error message text
I just figured out what is the problem, but i don't know why it happens and why.
it always remove the first 6 characters. why this happens
well I figured out the problem.
it was a but in org.apache.struts2.interceptor.validation.JSONValidationInterceptor
it removes the 6 first characters because of this incomplete if statement
sb.append((validationAware instanceof ModelDriven) ? ((String)fieldError.getKey()).substring(6) : (String)fieldError.getKey());
this error is fuond in struts 2.1.8
it should be like this
sb.append(((validationAware instanceof ModelDriven)) && (fieldErrorKey.startsWith("model.")) ? fieldErrorKey.substring(6) : fieldErrorKey);
it was corrected in later struts releses. i corrected the problem. and i thought i have to share the information for people who faces the problem.

How to Display Conditional Plain Text with Razor

I am having issues with displaying (rather NOT displaying) plain text in an else block.
if (Model.CareerFields != null && ViewBag.CFCount > 0)
{
<h3>Careerfields Listing</h3>
<table>
<tr>
<th></th>
<th>Careerfield Name</th>
</tr>
#foreach (var item in Model.CareerFields)
{
<tr>
<td>
#Html.ActionLink("Select", "Index", new { careerFieldID = item.CareerFieldId })
</td>
<td>
#item.CareerFieldName
</td>
</tr>
}
</table>
}
else
{
No Careerfields associated with #ViewBag.SelectedDivisionTitle
}
The if blocks works fine. The text only renders when true. However, the else block text renders when the page loads, not if it evaluates to false only.
I've tried using
Hmtl.Raw("No Careerfields associated with ")
<text>No Careerfields associated with #ViewBag.SelectedDivisionTitle</text>
#:No Careerfields associated with #ViewBag.SelectedDivisionTitle
But it still renders the plaintext before evaluation.
Any suggestions?
Put your "plain text" inside of a naked <span> tag:
else
{
<span>No Careerfields associated with #ViewBag.SelectedDivisionTitle</span>
}
The browser shouldn't render it special (unless you have css selecting every span) and it'll help razor sense the end of the C# and print your HTML.
The following code worked perfectly for me:
#if (false) {
<h3>
Careerfields Listing
</h3>
<table>
<tr>
<th>
</th>
<th>
Careerfield Name
</th>
</tr>
</table>
}
else
{
#:No Careerfields associated with #ViewBag.SelectedDivisionTitle
}
You can see that the contents of if are rendered when you change condition to true.
Looks like you've forgotten the # sign before your if statement. Try this:
#if (Model.CareerFields != null && ViewBag.CFCount > 0)
{
<h3>Careerfields Listing</h3>
<table>
<tr>
<th></th>
<th>Careerfield Name</th>
</tr>
#foreach (var item in Model.CareerFields)
{
<tr>
<td>
#Html.ActionLink("Select", "Index", new { careerFieldID = item.CareerFieldId })
</td>
<td>#item.CareerFieldName</td>
</tr>
}
</table>
}
else
{
<text>No Careerfields associated with #ViewBag.SelectedDivisionTitle</text>
}
The most concise and correct answer is:
Prepend #: before the text.
(note the : after the #)
This still allows to embed variables in the text by prepending an # to the variable name:
#if (someCondition)
{
#:Some text you want to see.
}
else
{
#:Some other text, with a variable #someVariable included in the text.
}

Resources