My Liferay entity Person has a <column name="mother" type="long" /> which points to the primary key of another instance of Person. This long shows up as a number in the SearchContainer table I created:
<liferay-ui:search-container-column-text
name="category"
property="category"
/>
Now, instead of showing up as a long I would like to display the name of the person. So I wrote:
<%
String motherName =
PersonLocalServiceUtil.getPerson( person.getMother() )
.getName();
}
%>
<liferay-ui:search-container-column-text
name="mother"
value="<%= motherName %>"
property="mother"
/>
PROBLEM: The values that get displayed in this column are still the long numbers, not the name. Even after rebuilding and restarting.
What am I doing wrong?
Check the implementation of SearchContainerColumnTextTag:
public int doEndTag() {
...
if (Validator.isNotNull(_property)) {
_value = ...
}
As you can see, you can't set both, property and value. Just set value and you are fine.
Related
I am using display tag and spring mvc.
Basically, i have a simple table like this. Note the use of external.
<display:table id="tableId" name="data" sort="external" defaultsort="1" sort="external">
<display:column property="id" title="ID" sortable="true" sortName="id" />
<display:column property="firstName" sortable="true" sortName="firstName" title="First Name" />
<display:column property="lastName" sortable="true" sortName="lastName" title="Last Name" />
<display:column property="address" sortable="true" sortName="address" title="Email Address"/>
</display:table>
On the controller side, i get the sorted column index and the sort order.
String c = request.getAttribute(new ParamEncoder("tableId").encodeParameterName(TableTagParameters.PARAMETER_SORT));
To get the order (ASC/DESC):
String order = request.getAttribute(new ParamEncoder("tableId").encodeParameterName(TableTagParameters.PARAMETER_ORDER)));
All this is working fine. For the last step i used customized comparator to sort my list and put it back into the attribute "data" mapped himself to the table (see display tag "name" property).
public void populateModel(Model model, HttpRequest request){
String c = request.getAttribute(new ParamEncoder("tableId").encodeParameterName(TableTagParameters.PARAMETER_SORT));
// here the comparator is computed with column and order value eg
Comparator comp = new DefaultComparator();
if(c == 1){
comp = new NumericComparator();
}
List<Employe> list = Collection.sort(dao.getEmployee(), comp );
model.addAttribute("data", list);
// here the list is sorted properly
return "mypage";
}
Unfortunatly the display in the final jsp does not care about order in the list. It seem's something is overriding to a default and alphanumeric sorter...so even if i use my NumericComparator the column is still wrong sorted and i assume the "list" object has been sorted back by the librairie before the display.
To summup:
Get display tag indexes : ok
Sort the list and put it back to jsp : ok (list is sorted depending on display tag params in the controller)
Display the sorted list in the jsp side with display tag : KO (the library do not care about list order, sorting it with default sort)
Display the sorted list in the jsp side without display tag : OK
Any got the explanation about this, is there something wrong or missing ?
Basic question, but haven't found any other relevant posts on SO.
I have this Spring code in my JSP with a property called vacant:
<form:hidden path="vacant" value="false"/>
And here is the generated output:
<input id="vacant" name="vacant" value="false" type="hidden" value=""/>
Why would value get printed twice with an empty second one?
(It's relevant because I'm trying to use the value in some Javascript.)
What you're seeing is "normal". According to the doc:
This tag renders an HTML 'input' tag with type 'hidden' using the
bound value
Let's assume vacant is Boolean vacant; in your DTO, since its value is null, the tag'll print it as value="". In addition, it'll print any other field you pass to it, e.g:
<form:hidden path="vacant" my-field="test"/>
<input id="vacant" name="vacant" my-field="test" type="hidden" value=""/>
So if you happen to use value in <form:hidden path="vacant" my-field="test" value="true"/>, it'll consider it an additional field:
<input id="vacant" name="vacant" my-field="test" value="false" type="hidden" value=""/>
Here is what happens in the source:
org.springframework.web.servlet.tags.form.HiddenInputTag
protected int writeTagContent(TagWriter tagWriter) throws JspException {
...
writeDefaultAttributes(tagWriter); // *) Here it'll print the value that you passed to the tag
...
//The next two statements get the bound value of vacant (null) and print it as value=""
String value = getDisplayString(getBoundValue(), getPropertyEditor());
tagWriter.writeAttribute("value", processFieldValue(getName(), value, "hidden"));
*) writeDefaultAttributes() calls writeOptionalAttributes(), where your passed value is printed (it's in this.dynamicAttributes along with my-field):
if (!CollectionUtils.isEmpty(this.dynamicAttributes)) {
for (String attr : this.dynamicAttributes.keySet()) {
tagWriter.writeOptionalAttributeValue(attr, getDisplayString(this.dynamicAttributes.get(attr)));
}
}
So, http:input is intended to be used for bound values, so set the value you need in the DTO before rendering the JSP.
Is there any way to suppress auto-generating ID attribute for elements while using th:field in Thymeleaf (2.1.4.RELEASE)? For example, given code:
<input type="text" th:field="*{year}" />
will produce the following HTML:
<input type="text" id="year" name="year" value="" />
What I want to achieve is (no id attribute):
<input type="text" name="year" value="" />
In JSP it was as easy as setting empty id:
<form:input path="year" id="" />
but Thymeleaf just replaces this empty attribute with the default-generated one.
Ok, I have looked inside the source code of Thymeleaf (2.1.4.RELEASE) and the method responsible for setting element id in Spring dialect is org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor.doProcess(...) (source on Github) that calls org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.computeId(...) (source on Github). If you look at computeId(...), you will see that there is no simple way to set empty id.
So we need to do it in not a simple way :) Here it is:
I created a custom dialect and defined a custom attribute noid. The markup looks like this:
<input type="text" th:field="*{year}" thex:noid="true" />
There is a great tutorial explaining how to create and use custom dialects in Thymeleaf and below is the most important part: attribute processor responsible for removing id attribute from given element.
Important things to note:
high precedence value (9999) guarantees that this processor will be executed as the last one (so no other processors will modify id after this one is executed)
modification type is set to substitution so we are completely replacing value of id element
removeAttributeIfEmpty(...) returns true, rather self-explanatory, remove attribute if empty
getModifiedAttributeValues(...) sets id to empty value and because above-mentioned method returns true, id attribute is removed
Code:
public class NoIdAttrProcessor extends AbstractAttributeModifierAttrProcessor {
public NoIdAttrProcessor() {
super("noid");
}
#Override
public int getPrecedence() {
return 9999;
}
#Override
protected ModificationType getModificationType(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return ModificationType.SUBSTITUTION;
}
#Override
protected boolean removeAttributeIfEmpty(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return true;
}
#Override
protected boolean recomputeProcessorsAfterExecution(Arguments arguments, Element element, String attributeName) {
return false;
}
#Override
protected Map<String, String> getModifiedAttributeValues(Arguments arguments, Element element, String attributeName) {
Map<String, String> values = new HashMap<>(1);
values.put("id", "");
return values;
}
}
If you dont want to use this in id of you input field just assign the value to only the th:name field,
<input type="text" th:name="*{year}" />
will give you output like,
<input type="text" name="2015" />
Or You can use a string at the end to make the id generate different from the name attribute like this
<input type="text" th:name="*{year}" th:id="*{year} + '-year' " />
will give you the output,
<input type="text" name="2015" id="2015-year"/>
I have a SqlDataSource defined in my aspx file that I use to call a StoredProcedure. It takes a hiddenField as its control parameter.
<asp:HiddenField ID="input" runat="server" />
<asp:SqlDataSource ID="source" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="sp" SelectCommandType="StoredProcedure">
<SelectParameters>
<asp:ControlParameter ControlID="input" Name="input" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
Is there a way I can grab that parameter from the ViewState instead? Preferably while keeping the datasource definition in the aspx file.
The solution in your case is very easy. Just create your own class inherit it from Parameter and override Evaluate method.
[DefaultProperty("ViewStateKey")]
public class ViewStateParameter : Parameter
{
public string ViewStateKey
{
get
{
return (string)ViewState["ViewStateKey"] ?? string.Empty;
}
set
{
if (ViewStateKey == value)
return;
ViewState["ViewStateKey"] = value;
OnParameterChanged();
}
}
protected override object Evaluate(HttpContext context, Control control)
{
if (control == null || string.IsNullOrEmpty(ViewStateKey))
return null;
return ViewState[ViewStateKey];
}
}
After that you will be able to use your parameter like following (just remember to register it at the top of your page or in web.config):
<asp:SqlDataSource ID="source" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="sp" SelectCommandType="StoredProcedure">
<SelectParameters>
<my:ViewStateParameter Name="input" Type="String" ViewStateKey="input" />
</SelectParameters>
</asp:SqlDataSource>
And your parameter will get its value from viewstate by key input.
I dont feel that the code for ViewStateParameter is of the first class. Maybe you will want to decorate it with more attributes and/or extra parameter checks with assertions.
I have similar problem. I dont want to use hidden fields to bind data source parameters because of security reasons.
I have googled one work-around - use asp:label instead of hidden field (make sure Visible=false). And then your label goes to view state and you can bind label to data source parameters.
When I enter 9:00 into the Start control, and 16:00 into Finish; the code below fails validation.
Does anybody know a way I can use the ASP.NET validator for times without the dates?
Start <asp:TextBox ID="txtStart" runat="server" /> (hh:mm)
<br />
Finish <asp:TextBox ID="txtFinish" runat="server" /> (hh:mm)
<br />
<asp:CompareValidator
id="cpvFinish"
ControlToValidate="txtFinish"
ControlToCompare="txtStart"
Operator="GreaterThanEqual"
Type="Date"
Display="Static"
EnableClientScript="true"
ErrorMessage="Finish time must be later than the start time."
runat="server" />
PS-I know I can easily use CustomValidator instead, it just seems like something this validator should be able to handle.
This appearently cannot be done.
For the record; I used a custom validator.
EDIT: Here's my custom validator code in case anyone (i.e. alhambraeidos) needs it. Please note, this code replaces my sample control names (txtStart & txtFinish) with actual names from my app (txtReady & txtClose).
try
{
// parse & compare dates
string randomDt = "01/01/2000 ";
args.IsValid = DateTime.Parse(randomDt + txtClose.Text) > DateTime.Parse(randomDt + txtReady.Text);
}
catch(Exception /*ex*/)
{
// exception is assumed to be invalid times entered
args.IsValid = false;
}
try to change the Type property to String, it should work.
Compare validator allowable types are:
Stinrg,
Integer,
Double,
Date (no time)
Currency