Wrong JSF 2 ID Chaining - jsf-2

Situation
JavaServer Faces Version: 2.1.6
I got a parent composite component with two nested cc. One of them contains a HtmlPanelGroup, which has a component binding. I use that binding to programmatically add HtmlCommandLink-Objects to the HtmlPanelGroup.
Let's call some IDs:
PARENT for the parent cc
CHILD_FIRST for the first child cc, nested in PARENT
CHILD_SECOND for the second child cc, nested in PARENT
GROUP for the PanelGroup, nested in CHILD_SECOND
LINK_1 for the first HtmlCommandLink-Object, progammatically added to GROUP
Expectation
I expect the following ID Chaining (with default javax.faces.SEPARATOR_CHAR):
PARENT (Composite Component, declarative)
PARENT:CHILD_FIRST (Composite Component, declarative)
PARENT:CHILD_SECOND (Component Component, declarative)
PARENT:CHILD_SECOND:GROUP (HtmlPanelGroup, declarative)
PARENT:CHILD_SECOND:GROUP:LINK_1 (HtmlCommandLink, programmatically)
Problem
The ID of the HtmlCommandLink-Object is wrong at the first page visit. Instead of "PARENT:CHILD_SECOND:GROUP:LINK_1" the ID is only "CHILD_SECOND:GROUP:LINK_1". After I refresh the page the ID is correctly "PARENT:CHILD_SECOND:GROUP:LINK_1". In fact every component in the second composite component ("CHILD_SECOND") is missing the first part of the ID ("PARENT"). After refresh all IDs are correctly.
Solution
I might automatically refresh the page after the first visit. But I don't want to.

the id after interpreted by the browser doesn't like what you thought. as far as i know it doesn't exceed 3 levels. For example:
<h:form id="form">
<h:panel id="panel">
<h:panel id="panel1">
<h:label id="lab"/>
</h:panel>
<h:panel id="panel2">
</h:panel>
</h:panel>
</h:form>
then the label's id will not be form:panel:panel1:lab but form:panel:lab. if the widget that you want to get the id is more deeper, then i can't tell but it won't exceed 3 levels. i can tell you how to find the id.
you can just write the page, and then view it on the chrome or firefox where you can see the source code after interpreted. so you can get the id you want.
good luck!

Related

JSF - how to properly use loops [c:forEach vs ui:repeat]

I'm trying to create a generic pageable table that will display any entity from database. I'm using annotations and reflection for that purpose. On the java side everything works fine, however I can't manage to create a view for my table. I tried two approaches, with c:forEach and ui:repeat:
Requirements for the view:
Fixed amount of records should be displayed on each page (eg. 10)
Components for browsing and editing table columns should be generated automatically based on viewed field type (field annotated in hibernate entity)
Additional column with actions should be added (removing, saving, filtering, adding entities)
Additional row for filtering and adding fresh entities should be added above table header
Each column has to be sortable
c:forEach approach problem:
When changing between pages that have different number of records, then proper records are displayed but number of rows is the same like on the previous page. If previous page had less records than next page will have less records than it should have and if previous page had more records than next page will have more records than it should have. However when I refresh the whole site on the given page everything renders properly.
On the first picture you can see, when I go to the last page unnecessary records are generated to match previous page size. On the second picture, page size is truncated to the last page size.
Table body code:
<tbody class="lot">
<c:forEach items="#{cc.attrs.wflBean.searchProvider.cells}" var="row" varStatus="rowStatus">
<tr>
<c:forEach items="#{row.cells}" var="cell" varStatus="cellStatus">
<td style="text-align: #{cell.alignment}; vertical-align: bottom;">
<h:commandLink action="#{cc.attrs.wflBean.editEntity}" value="Edit" styleClass="none"
rendered="#{cc.attrs.wflBean.isExternalEditSupported and cc.attrs.wflBean.canEdit}">
<f:setPropertyActionListener target="#{cc.attrs.wflBean.currentEntity}" value="#{cell.entity}"/>
</h:commandLink>
<!--TODO: cellIndex will not work properly for more then 10 columns/rows-->
<comp:pagableTableCell wflBean="#{cc.attrs.wflBean}" cell="#{cell}"
cellIndex="#{cellStatus.index}#{rowStatus.index}"
canEdit="#{not cc.attrs.wflBean.isExternalEditSupported and cc.attrs.wflBean.canEdit}"/>
</td>
</c:forEach>
...CODE FOR ADDING ADDITIONAL ACCTIONS...
</c:forEach>
</tbody>
pagableTableCell is a custom component that renders proper component for editing cell value it is done with c:choose/c:when/c:otherwise tags. When changing page, the cells are retrieved. Its done during RESTORE_VIEW and RENDER_RESPONSE phase. Cells for new page are recalculated and returned properly during RENDER_RESPONSE phase. Also, I read that c:forEach tag is evaluated during build view phase but I don't see what javax.faces.event.PhaseId is that? Page is set by another custom component and it is done properly right before RENDER_RESPONSE phase.
ui:repeat approach problem:
With this approach I replaced c:forEach with ui:repeat and c:choose/c:when/c:otherwise with ui:fragment but then, I can't evaluate EL expression within id attribute, to make it unique, for date component that you can see on images above. Unique id is required for date component to work properly. Is there any way to manually generate component id when using ui:repeat?
Overall I don't know how should I approach this problem. c:forEach seems to work better for me, at least table is usable. Could you advise me how to fix one of this problems?
Thanks,

Difference in navigation by action="xyz" and action="#{bean.returnXyz}"

How is navigation from a Facelet page
<p:commandLink action="xyz.xhtml">
or a backing bean
<p:commandLink action="#{bean.redirect}">
public class Bean{
public String redirect(){
.....
return "xyz.xhtml";
}
}
different from each other?
How is navigation from a xhtml page or a backing bean different from each other.
There's no difference. The both examples invoke a POST request and instructs JSF to render the view associated with the given outcome. The backing bean method has the only advantage that it allows you to perform some business logic beforehand or even control the outcome value programmatically.
However, if you don't have any business logic at all and solely want to have an idempotent link to another page, then using a command link is actually a bad practice. Using POST for page-to-page navigation is not user nor SEO friendly. The target page is not bookmarkable (the URL remains the one of the page where the POST form was been submitted to) nor searchbot-crawlable (it is using JavaScript to submit a hidden form).
You should instead use a normal link.
<h:link outcome="xyz.xhtml">
This generates a SEO-friendly <a> element with the full URL in its href and ends up in an user-friendly bookmarkable URL.
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Check out the documentation of p:commandLink here, which says the following for action attribute:
A method expression or a string outcome to process when command is
executed.
Now, as action="xyz.xhtml" returns String xyz.xhtml you're redirected accordingly and for action="#{bean.redirect}" which again returns xyz.xhtml you are again redirected according to the returned String.

How to iterate over variable in param using JSF EL expression

I have a PrimeFaces <p:dataGrid> component that contains a variable number of panels. Each panel contains a number of derived components. I have a delete button contained inside each of these panels to allow for deletion. I also have an add button outside of the dataGrid. Instead of using immediate="true" on the buttons, I figured out how to set the required attribute of each component in each panel.
For instance:
required="#{empty param['vehicleGrid:0:btnDelete'] and empty param['btnAdd']}".
For every delete button in the dataGrid and the add button, ignore component validation.
This works if there is a panel inside of the dataGrid, but it only references the first one. I need to dynamically check every panel. Maybe instead of looking at it from the markup page, maybe I need to look at it in Java terms since param is a Map<String, String>.
Bind the delete button component to the view and use UIComponent#getClientId() instead.
<h:inputText ... required="#{empty param[deleteButton.clientId]}" />
...
<h:commandButton binding="#{deleteButton}" ... />
This way the proper client ID will be looked up in the parameter map and there's then no need to iterate over the parameter map.

Multiple instance of partial razor form

I have 2 nested partial controls
User Control1:
Html.BeginRouteForm
(
Html.RenderPartial (path of child form)
)
ChildControl:
Html.LabelFor(x=>x.FirstName,"First Name")
Html.TextBoxFor(x=>x.FirstName)
...
Problem:
I have 2 instance of this partial control on home page. When I click on Submit button of second instance, form is posted using AJAX & JQuery. Since FirstName has a required constraint, form renders back with required validation triggered for FirstName. Here comes the issue: When I click on label "First Name", cursor gets focused on First Name TextBox of first instance of partial form instead of second instance where validation triggered.
Any suggestion on how to tackle this?
Thanks a lot!
At a guess, I'd say you're the victim of a duplicate ID, because the two instances of ChildControl are likely generating the same ID string.
Unlike ASPNET, MVC appears to generate IDs "locally". In other words, nothing behind the scenes keeps track of how many "controls" are generated, which is what allows ASPNET to generate unique ids.
If so, it's an easy enough problem to solve. Just add your own ID to each instance of ChildControl, doing something like the following:
#Html.TextBox("rel_date", Model.Value.rel_date.ToSiteString(), new { #class = "date-picker", style = "width: 75px;", id = "" })
Here I'm actually suppressing the ID on a textbox I'm generating by passing in an empty ID value in the html attributes parameter of the TextBox helper call. You'd insert some ID which you know to be unique to the page.
BTW, you can quickly check to see if I'm right about the duplicate IDs by checking the generated html for the page. When it's up in IE just hit F12 (in IE9 anyway). That'll open a window which allows you to browse the html that's generating your page. You can read it to see if the ID attributes of the two textboxes are the same, which would support my theory.
Good luck!

Selenium and JSF 2.0

When I a generate SelectOneMenu with JSF2.0 the the id I specified in the xhtml is attached to a generated ID from JSF.
e.g. out of my_fancy_id it generates j_idt9:my_fancy_id
Now I want to test my page with Selenium 2 Web Driver. I try to re-find my select menu:
driver.findElement(By.id("my_fancy_id"));
Of course it does't find anything because the id is changed. What is the best way to find the select menu on the page?
Usually the id of the form is prepended to all element ids inside the form. If you don't set a form id, JSF does it for you (the 'j_idt9'). Solution: Assign an id to your form and try to use the full id in your findElementmethod, e.g.:
<h:form id="myForm">
...
</h:form>
Call it this way:
driver.findElement(By.id("myForm:my_fancy_id"));
or you can add <h:form prependId="false"> so that the id of the form does not get prepended
You set the component identifier on controls; the renderers emit the client identifier to the markup.
This allows JSF to emit valid HTML ids (they must be unique) even in the face of templates and complex controls. A control will be namespaced by any parent that is a NamingContainer (such as a form).
In some containers, the client identifier will be namespaced by the view, but this generally only happens in portlet environments.
Some component libraries (like Tomahawk) have a forceId attribute, but care must be exercised in using them. I wrote a more extensive post on client identifiers here.

Resources