JSF: Custom component in tables not rendered as expected - jsf

Is there a suitable solution for the custom component root-issue in the meanwhile?
In short terms, the problem is that using custom components containing of both a label and an input field within a table like
<h:panelGrid columns="2">
<jl:inputField value="#{testBean.value1}"/>
<jl:inputField value="#{testBean.value2}"/>
</h:panelGrid>
... will be rendered within a single row.
A dirty solution would be to place the panelGrid within the component which will cause a rendering of a separate table for each input field. This is most likely the case cause there isn't a bottom-up but a top-down approach when parsing the code.
Do you have any other ideas how to handle this? Custom tags were mentioned in the discussion.

Related

Refactoring a DataTable with a large number of attributes

I've got a data table with 17 attributes. The table can be rendered in two modes: with row selection enabled and without it.
<p:dataTable selection="#{isDefaultSelectionMode ? null : widget.selected}" />
It doesn't work because selection expects a reference to a property to be able to set/get it.
I could create a dummy property widget.ignored and it's going to work. I don't like this for the obvious reason.
<p:dataTable selection="#{isDefaultSelectionMode ? widget.ignored : widget.selected}" />
I could split the table into two separate templates. I would exclude selection from one and duplicate 16 other attributes. It's not a good one, either.
I am looking for an elegant solution to either make the attribute optional (not to render it under some condition) or to avoid defining a dummy property.
I am new to JSF and PrimeFaces, feel free to correct. Any help would be welcomed.
Fortunately, I didn't have to apply any of my terrible workarounds.
As suggested by #Kukeltje (thank you) and the links he provided, I defined the attribute conditionally
<c:if test="#{isDefaultSelectionMode}">
<f:attribute name="selection" value="#{widget.selected}"/>
</c:if>
For more details, visit these questions:
JSF 2.0 dynamic attributes without creating new components
How not to set an attribute of a component inside a composite component if it is empty?
What is f:attribute used for in this example?

JSF best practices : One form for the whole application or a few smaller forrms?

What is the best practice in JSF , to create one main <h:form> in template for example and put all content inside or to have a few forms for each parts, for example if we have two logical blocks of code on the page we should have wrapped these blocks in 2 separate forms ???
This is an overly broad question, and it as well has nothing to di with JSF. It is a question of HTML understanding and design.
If you abstract away all of the JSF details, you'll find out that the rendered component is a plain HTML <form>. To recall the specification, a form is:
a section of a document containing normal content, markup, special elements called controls (checkboxes, radio buttons, menus, etc.), and labels on those controls. Users generally "complete" a form by modifying its controls (entering text, selecting menu items, etc.), before submitting the form to an agent for processing (e.g., to a Web server, to a mail server, etc.)
So ultimately a whole form will be submitted to the server. In case of a component-based framework, like JSF, the bound values of components will populate the backing beans with the submitted data, in case there are no errors.
But what data will be submitted? All data that is within a form. So, if you have one global form that means that all unrelated pieces of information will be collected: like user credentials, product choices, selection of preferences, etc. And it will be done all at once. Most probably it won't yield the desired functionality, but will produce unexpected results.
The problem there was mixing of concerns: one form contained non-related data that was not designed to be submitted together. This leaves us with a one-form-per-user-interaction, like one form for user authentication/logout, another form for storing user preferences, yet another one for keeping product choices, etc. One global form also is likely to leave you with nesting forms problem, taking you some time to figure it out.
Regarding the choice of where to put that form, it is as well depending on the logical separation: if you have user login/logout on every page it could be placed in master template. Per-view forms are likely to be put in template client. Moreover, you'll find it convenient to sometimes put them side-by-side to distinguish the functionality.
Also, form may alter the expected behaviour. One final example: user choice of products. Consider two cases.
The first one:
<h:form>
<ui:repeat value="#{bean.purchasedProducts}" var="product">
<h:outputText value=#{product.name}/>
<h:inputText value=#{product.quantity}/>
<h:commandButton value="Change"/>
</h:dataTable>
</h:form>
The second one:
<ui:repeat value="#{bean.purchasedProducts}" var="product">
<h:form>
<h:outputText value=#{product.name}/>
<h:inputText value=#{product.quantity}/>
<h:commandButton value="Change"/>
</h:form>
</h:dataTable>
While the first example will update all products, the second one will update only the relevant product.
Finally, there is no 'best practice' or 'universal solution'. I think that it's best to depart from separation of concerns when designing an HTML document.
And, yes, I'm voting to close the question.

Conditional string concatenation/building in JSF

I'm trying to convert a JSP Page to JSF (no JSP code allowed), but have stumbled upon an issue.
Note: This is academic, so no "dirty" solution will do.
I have jsp code that sets the image source and alt text of an image depending on various conditions. There are concatenations and switch conditions. This is inside a loop.
Now, I can reproduce the loop that goes through all the values, like this:
<ui:repeat value="#{gameapi.game.fieldsList}" var="field">
<h:graphicImage id="field#{field.fieldNr}" styleClass="field#{field.fieldNr}"
url="..." alt="" title=""/>
</ui:repeat>
However, there's a total of over 20 combinations for the image url and alt text. Obviously, I doubt writing a conditionally rendered or chosen graphicImage Tag for every possibility is an elegant solution, since this would only get uglier with every additional combination.
I also cannot create those strings in the underlying java code, since that would violate the idea of separating view, model and controller.
So what is the best solution to do this? It seems like a huge weakness of JSF.
Consider using a variation on the MVVM pattern. You can have managed beans that are dedicated to view logic separate from the business logic managed beans.
<ui:repeat value="#{bizBean.list}" var="_row">
<h:graphicImage
url="#{viewModelBean.images[_row.outcome]}"
alt="#{viewModelBean.alts[_row.outcome]}"
title="#{viewModelBean.titles[_row.outcome]}" />
</ui:repeat>
viewModelBean could be an application-scoped type with a bunch of map properties. This assumes a relatively simple case, but the pattern is suited to more sophisticated requirements.
Note: the repeating control should be a NamingContainer, so trying to set the client identifier in the VDL is redundant. See here for more.

Seam conditional render without parsing

I'm trying to make a conditional render in my Seam application (2.2.0), to display two different controls depending on a condition.
I'm using the s:fragment tag with the render attribute, but my problem is that I want whatever the control is displayed, to have the same id:
<s:fragment render="${editable}">
<rich:calendar id="entityDate"..../>
</s:fragment>
<s:fragment render="${!editable}">
<h:outputText id="entityDate".../>
</s:fragment>
My problem is that even when the render attribute set to false, the "not to be rendered" element is parsed, and I get an exception because of the duplicated id.
I also tried with the tag <ui:remove>, which effectively removes the element before the parsing phase, so I can have something like:
<span id="myId"/>
<ui:remove>
<span id="myId"/>
</ui:remove>
Unfortunately the <ui:remove> tag doesn't allow conditional logic. Has anyone found a way to solve this?
That's only possible when you use a view build time tag such as JSTL <c:if>.
<c:if test="#{editable}">
<rich:calendar id="entityDate" />
</c:if>
<c:if test="#{!editable}">
<h:outputText id="entityDate" />
</c:if>
(note that this is not going to work within an iterablte JSF component, such as <ui:repeat>, <h:dataTable> and so on)
After all, I strongly recommend to take benefit of the disabled attribute instead, if necessary with a good shot of CSS to hide the input field borders and so on. It'll minimize the JSF view boilerplate code.
<rich:calendar id="entityDate" disabled="#{!editable}" />
Disabled inputs are separately styleable by the CSS attribute selector element[attribute], e.g.
input[disabled] {
border: 0;
}
The above removes the border of input elements with the disabled attribute present so that it look like a normal output text.
"Solve"? There is nothing to solve here: two elements in a GUI can not have the same ID. Hardly unnatural or unsound?
It's like asking: "I have a database table with two rows, I would like them both to have the same primary key value, but somehow I get these errors... has anyone managed to solve the problem and circumvent the constraints?".
Or even closer analogy: "I have two spans, one of them is invisible (has style="display: none") I would like them both to have the same id - and browsers seem not to like it, despite one of the spans being invisible".
Bottom line: rendered on not rendered, each component is still a part of the view tree, and therefore has a UNIQUE id.
I have a suspicion that you want to have some "polymorphic" code that should work with the currently visible element. Using ID for such code IS WRONG. If you show us your use case, we might find a right way to achieve the effect.
I use selenuim myself in a seam environement and i recommend using defined ids whenever possible. First you have the ability to create smaller ids which is usefull for pagesize. Second the selenium test run alot faster if you use ids for referencing instead of other selectors. I have not yet found a selenium test where you cannot handle diffrent ids. Additionally if a code fails in jsf tree creation you see which id is failing.
I see you are using sfragment with editable or not. I use the sdecorate and give the decorate an id and then "just" ed for the input and vi for the outputtext for example. This makes it easy in selenium to check the availability of edit or view components.
Would you be able to get the same results you need by putting the id tag on the fragment?
So:
<s:fragment id="entityDate">
<rich:calendar render="${editable}" />
<h:outputText render="${!editable}" />
</s:fragment>

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:

Resources