Best way to make an expandable/collapsible subTable with rich:dataTable - jsf

I've recently ported an application from JSF 1.1 to JSF 1.2. In the process we removed tomahawk and decided to use rich instead.
Now I need a way to make an expandable/collapsible detailViev for each row in the table.
The only thing I can think of is something along these lines (adapted from documentation at docs.jboss.com):
<rich:dataTable value="#{capitalsBean.capitals}" var="capitals">
<rich:column>
...
</rich:column>
<rich:subTable value="#{capitals.details}" var="detail" ajaxKeys="#{bean.ajaxSet}" binding="#{bean.subtable}" id="subtable" rendered="detail.detailOpened">
<rich:column>
...
</rich:column>
</rich:subTable>
</rich:dataTable>
I guess something like that would work. The problem is that I either have to add a getDetailOpened and a setDetailOpened to the objects I use, or wrap each object in another object that provides those two methods.
Anybody knows a better way, or how it is supposed to be done?

I've often added methods to my beans (or wrapper beans) which contain those properties as a way of working around JSF. It's not pretty but it works.
The only other option I can think of at the moment is to use a JavaScript function to toggle the state of the details view. That wouldn't be ideal for a number of reasons but it would save you having to keep state server-side.

Related

Global date/boolean formatting in frontend of JSF application

I am developing a JSF dashboard web application which includes several very large PrimeFaces datatables. It would be really handy if I could set a global format for the representation of certain types – currently the only way I can think of is having backing bean methods like
public String formattedBoolean(Boolean inputBoolean) {
return inputBoolean ? "Yes" : "No";
}
which I could then manually call from the frontend (and similarly, I could use f:convertDateTime components for formatting date objects as string). However, this type of approach would require adding a lot of boilerplate XHTML, such as
<p:column headerText="Start Date" id="startDate"
sortBy="#{dataContainer.startDate}"
filterBy="#{dataContainer.startDate}">
<h:outputText value="#{dataContainer.startDate}">
<f:convertDateTime pattern="yyyy-MM-dd"/>
</h:outputText>
</p:column>
which I'd rather avoid. Does anyone know if there is a more elegant way of globally overriding the default Java string representation of objects in the frontend, or at least within the context of a data table?
Following advice above, I have decided to override the default FacesConverter for the given classes, as these are formats I'd want to present consistently in text throughout the application.

What does <f:facet> do and when should I use it?

I have been having trouble with the tag <f:facet>. I am working form other examples of code which use it, but I'm not sure exactly what purpose it serves.
I have written some code which in method is exactly the same as other code I have seen which works, except there's is wrapped in a <f:facet name=actions> tag. When I add this around my code the drop down box I am wrapping it around disappears when I deploy. Anyone able to suggest a reason for this or give me an insight into how and when to use facet?
Here is my code, I won't bother adding the bean code as they're just basic getters and setters and I don't think they're causing the trouble.
<f:facet name="actions">
<p:selectOneMenu id="SwitchWeekDrpDwnMenu"
value="#{depotWorkloadBean.selectView}"
partialSubmit="true">
<p:ajax update="mainForm"
listener="#{depotWorkloadBean.updateView}" />
<f:selectItem itemLabel="Day view" itemValue="Day"/>
<f:selectItem itemLabel="01/01/2014" itemValue="Week"/>
</p:selectOneMenu>
</f:facet>
If I remove the facet tag the dropdown box displays, but doesn't function as it should with the beans.
A facet represents a named section within a container component. For example, you can create a header and a footer facet for a dataTable component.
https://web.archive.org/web/20170828020413/http://www.jsftoolbox.com/documentation/help/12-TagReference/core/f_facet.html
It's useful when you want to create component that uses some code from user (let's say wrapper).
ie. when you want to create component that hides long text and shows short version of it. You can use just the element body, but then you will get only one value, if you want to get from user the short AND the long version then you can not do it in one value (without using some discriminant), just use facet and say which one is the long and which is the short version.
<textShortener>
<f:facet name="short">
This text is short.
</f:facet>
<f:facet name="long">
This text is too <b>long</b> to be showed when page loads. User have to click the button after the short text to show this.
</f:facet>
</textShortener>
Yes, this can (and should) be done with jsf templating, but I hope you got it.
To question: you defined facet just in the wild xml, nobody requested it so nobody processed it - that's why it did not throw error nor showed anything.

JSF composite:insertFacet and composite:renderFacet

I want to have a composite component with a facet in it, which I implement in my "implementation" of this composite component. My problem are ids, because when I only define in my composite component and then with put my implementation in it, it only renders it but the component is in another place.
Here is a sample code:
myComposition.xhtml
<composite:implementation>
<composite:renderFacet name="myFacet">
</composite:implementation>
myCompositionImpl.xhtml
<mySomething:myComposition>
<f:facet name="myFacet">
this code is rendered but the "component" which I define here is not placed
logically in the place where I defined the "renderFacet".
</f:facet>
</mySomething:myComposition>
What can I do about this? With composite:insertFacet it doesn't render anything. I need to have the component also there because I need to know the client id of it.
Just to clarify:
Did you specify <cc:facet name="myFacet"> within the interface of the component?
Furthermore what exactly do you mean with in another place?
Some tips:
renderFacet is correct, insertFacet is for facets defined within the composite itself.
Try adding "<!-- -->" as the first line of content of your facet, this suppose to be a workaround for a bug regarding single line facet content.
I got it working. The problem was I had to figure out the clientId of the facet inserted and I didn't know that each composite-component makes it own NamingContainer.
I had something like that:
"myComposition2.xhtml"
...
"index.faces"
and the resulting clientId was: myC2:myC1:

Why prependId="false" in a jsf form?

I know what prependId="false" does. It set the flag so that the id of the form does not prepend the id of the form child, but why? any particular reason why you do or dont want to prepend id?
In my experience, I never use this attribute. However, in some cases it can be useful.
When you use Facelets, you can create templates or include pages inside another page. So you can imagine that a page could be included in several different pages. Take the example where the parent pages contain a form, with different id:
Page 1:
<h:form id="form1">
<ui:include src="pages/my-page.xhtml"/>
...
</h:form>
Page 2:
<h:form id="form2">
<ui:include src="pages/my-page.xhtml"/>
...
</h:form>
Now, in the my-page.xhtml, you have a <h:inputText id="foo"/>. In the first case, the real ID of the input will be form1:foo, while in the second case, it will be form2:foo. This could create complex situations if you need a direct access to this component in Javascript or in Java (using findComponent("...") method).
If you use prependId="false" (or on some components forceId="true"), the real ID will be simply foo, and then your code will be simpler as you will not have to care about the container of the input field.
However, you will have to use this attribute carefully, as you may get a duplicate ID error if you use this prepend attribute too often...
In modern jsf versions it might also break ajax, see UIForm with prependId="false" breaks <f:ajax render>
A situation where prependId=false is useful is in the login form, if you are using Spring Security, because the ids of the inputtexts have to be exactly "j_username" and "j_password". So you shouldn't put the form id before them, and using prependId=false is a good choice to acheive this.
I prefer to add prependId occasionally to make styling elements via their ID classes easier. For example, a form:
<h:form id="myform" ... >
<h:inputText id="mytext" ... />
</h:form>
Would give you an ID of myform:mytext. As the colon is reserved in CSS, you have to escape the CSS to read something like #myform\:mytext { ... } which I prefer not to do. With prependId="false" I get to use just #mytext { ... } which is much simpler & nicer to read. It also plays nicer with CSS preprocessors like LESS or Sass.
One scenario where we have to set this flag is in case of Autocomplete control of primefaces library.
I had to set this flag to false when I was trying AutoComplete control of primefaces library. I was not able to get autocomplete working but after setting this flag it worked fine. You can see this link to my question regarding this problem
WARN [Parameters] Parameters: Invalid chunk ignored. warning coming in primefaces application
In addition to making for CSS selectors easier, using prependId=false makes it easier to use JavaScript and jQuery to access specific elements.
Otherwise, without using RichFaces, to get at an elmement by id using jQuery you'll have to use an ugly escape sequence like:
jQuery("form-id\\:element-id")

JSF, how to use EL in onclick

I want to create links using database columns. I have a backing bean where I 'm connecting to the database. There is no problem with the connection and also no problem with the links names. I can see my links on my browser. I want to use onclick function and that's exactly where the problem starts. How can I use or can I use EL in onclick?
A little example:
<h:dataTable rows="7" value="#{frontSiteMenu.links}" var="row"
styleClass="sitemenu" width="200">
<h:column>
<h:outputText value='#{row.newsGroup}' />
</h:column>
</h:dataTable>
Thanks.
I take it you are using JSPs?
Use h:outputLink instead of an a tag and change the expression use the # character:
<h:outputLink value="#" onclick="dispNewsGroup('#{row.newsGroupId}')">
<h:outputText value='#{row.newsGroup}' />
</h:outputLink>
That is untested, but should be close to what you want.
The spec says this about # vs $:
...by convention the J2EE
web tier specifications use the
${expr} construct for immediate
evaluation and the #{expr} construct
for deferred evaluation.
So, in a repeat control where the underlying values change, it is desirable to use deferred evaluation.
There are also issues with using non-JSF tags as children of some JSF controls, so it is best to stick to using JSF controls where possible (though there is a f:verbatim tag). Many of these issues go away if you move to the newer Facelets view technology.

Resources