action isn't invoked at the first click - jsf-2

i have a page with authentification which forword to my template page where there is menus.
<navigation-rule>
<from-view-id>pages/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>userOK</from-outcome>
<to-view-id>pages/template.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>userNOK</from-outcome>
<to-view-id>pages/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
my page template.xhtml
<h:form>
<p:menu type="plain" style="width:200;box-shadow: 6px 6px 6px black;top:-18;left:-40" >
<p:submenu label="Dossier" id ="Dossier" >
<p:menuitem update=":contentform,:messages" value="Nouveau Dossier" action="#{choix.setPage('ajoutDossier')}"
....
....
</h:form>
<h:form id="contentform" >
<h:panelGroup rendered="#{choix.page == 'ajoutDossier'}">
<ui:include src="Dossier/ajoutDossier.xhtml" />
</h:panelGroup>
....
....
</h:form>
the problem is that action isn't invoked at the first click i have to click 2 time , and before i click many time and action isn't invoked, and sometimes juste p:submenu which are in the last position work
also when it was no forward just the page template.xhtml it's work !

You are not taking advantage of JSF templates. Instead of using a template and several template clients you have everything in one page; and render stuff conditionally. Look this tutorial or any other tutorial about jsf tempaltes.
Normally you would have a template, which has all the layout and content common to all pages; and uses the tag <ui:insert name="title" >Default content</ui:insert> as many times as you need (with different names). Then you create a template client, defining the template using
<ui:composition template="./../resources/templates/templateFile.xhtml">
And then use the tag <ui:define name="nav2"> to set the content to include in the template.
Besides that, about the problem with navigation in your code: when you do a navigation you don't update content, because after a navigation the page is completely loaded (no ajax). So first of all you have to remove your update attribute; and also you have to set the "ajax" attribute of p:menuitem to false; because by default it's true. otherwise navigation will not take place.
the redirect attribute in the navigation rule is not required if you did things ok. It can work perfectly fine with a forward. The only problem with forward is that the browser URL will not change, because browser is not notified of the navigation.

i found the solution i have to add <redirect /> after the <to-view-id> of page which have the problem, because i read that JSF uses internal FORWARD instead of REDIRECT to navigate to the success page and this why the URL will not get changed but i don't really undestand why ??
here is the code who work :
<navigation-rule>
<from-view-id>pages/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>userOK</from-outcome>
<to-view-id>pages/template.xhtml</to-view-id>
<redirect />
</navigation-case>
<navigation-case>
<from-outcome>userNOK</from-outcome>
<to-view-id>pages/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
also to not loose css of redirect page i have to add this
<link rel="stylesheet" href="#{request.contextPath}/css/style.css" />

Related

rich:menuItem action doesn't redirect without navigation-rule

In JSF I want to redirect a page from a dropdown menu. It redirects when I use faces-config using navigation-rule:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>test</from-outcome>
<to-view-id>/pages/design/TestDetails.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
But when I try to pass the URL directly, I'm not able to redirect:
<rich:menuItem label="someLabel" action="/pages/design/TestDetails.xhtml" />
What is the fault in my code?
Just new to RichFaces, found out below solution with javascript, seems working:
<rich:dropDownMenu mode="client" label="Navigate">
<rich:menuItem label="Page - 1" onclick="document.location.href='samplePage.jsf'" />
<rich:menuItem label="Page - 2" onclick="document.location.href='samplePage2.jsf'" />
</rich:dropDownMenu>
Basically you should use navigation-rule in JSF's action fields (that's what they're for). But if you want to put URL directly then just add ?faces-redirect=true to it (the equivalent of <redirect/> in navigation-rule):
<rich:menuItem label="someLabel" action="/pages/design/TestDetails.xhtml?faces-redirect=true" />
(Notice that you need to put full path not just TestDetails?faces-redirect=true as #Omar suggested in comments.)
Also: <from-view-id>*</from-view-id> can be ommited in rules like this one.

UI Repeat varStatus not working in CompositeComponent

I use JSF 2.0 (Apache myFaces) on WebSphere Application Server 8.
I have a bean which contains a list of charts (data for jquery HighCharts).
For each chart I need some JSF components + one Highchart Wrapper written as CompositeCompoent (look here)
So I use the ui:repeat function of jsf 2 like this:
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:hc="http://java.sun.com/jsf/composite/chartComponents"
template="/template/mytemplate.xhtml">
<ui:define name="content">
<ui:repeat value="#{chartCtrl.charts }" var="chart" id="chartrepeat" varStatus="chartStatus">
#{chartStatus.index }
<h:form id="chartform_#{chartStatus.index }">
<!-- some jsf select stuff-->
</h:form>
#{chartStatus.index }
<hc:Chart title="Statistics" id="hcchart_#{chartStatus.index }"
<!-- here's the problem-->
<ui:repeat value="#{chart.series }" var="serie">
<hc:ChartSeries series="#{serie.data }" />
</ui:repeat>
</hc:Chart>
#{chartStatus.index }
</p:panel>
</ui:repeat>
<h:outputScript library="js" name="highcharts.js" />
<h:outputScript library="js/modules" name="exporting.js" />
<h:outputScript library="js" name="jquery-1.9.1.min.js" target="head" />
</ui:define>
</ui:composition>
The #{chartStatus.index } works every where but not in hc:Chart id="".
The generated js and div by this CC contains the id 'hcchart_chartdiv'. The index of the current repeat left.
How can I pass the correct number to the id attribute?
EDIT: Composite Component
Here is a part of the hc:Chart where the ID should be used
<cc:implementation>
<div id="#{cc.id}_chartDiv" />
<!-- Highcharts -_>
<script type="text/javascript">
$(function() {
// Data must be defined WITHIN the function. This prevents
// different charts using the same data variables.
var options = {
credits : {
enabled : false
},
chart : {
renderTo : '#{cc.id}_chartDiv',
....
</script>
When I leave the attribute id in hc:Chart empty, then the generated ID is something like "j_id568185923_1_5f9521d0_chartDiv". But still without :row:.
EDIT 2: IndexOf Approach
I tested another approach to set the ID of my chart.
id="hc_#{chartCtrl.charts.indexOf(chart) }"
I tried to use the IndexOf method of my ArrayList. I implemented HashCode und Equals method in all Classes. When I test it, it works fine.
But when I use it with EL I get -1 returned.
Solution
Just as BalusC said I cant use the ID tag for EL. So I simple created a new attribute in my CC. That works fine (just so easy).
Thanks BalusC.
Does someone has another idea?
The id attribute is evaluated during view build time. The <ui:repeat varStatus> is set during view render time which is after view build time. Essentially, you've the same problem as explained in detail here: JSTL in JSF2 Facelets... makes sense?
Any EL expression in the id attribute must be available during view build time. If you replace <ui:repeat> by <c:forEach> which runs during view build time, then the id must be properly set. An alternative is to just get rid of EL in those id attributes based on <ui:repeat varStatus>. JSF will already automatically suffix the IDs of <ui:repeat> child components with the row index.
Note that the <c:forEach> may have unforeseen side effects when used in combination with view scoped beans and partial state saving enabled. See the aforelinked answer for details.

JSF datatable with paging and sorting and browser-back

We are using Primefaces datatable component with sorting, pagination and a LazyDataModel in order to display search results. The backing bean of the search page is ViewScoped.
From the search result list a user can select a result item in order to view the details. This is implemented as a new page request, e.g. <h:link value="Show Details" outcome="showDetails?id=11234"/>. By clicking the browser back button the user will navigate back to the search result list.
The problem is that the datatable will be in initial state again, so it wont display the last selected sort order and page. This is the case in most browsers, only Firefox 11 seems to keep those DOM changes in cache. Neither IE nor Chrome.
Does anybody has a good approach how to handle this? We actually don't need "ajaxified" sorting and paging. We would prefer handling everything through ViewParams, but this seems not to be supported by primefaces.
I ran into this as well, and I developed a coding pattern that might help. It isn't really a PrimeFaces thing (which I am using as well) -- more of a technique for using book-markable links with JSF 2.
In the markup, I include all the parameters for the page as follows:
<f:metadata>
<f:viewParam name="orderID" value="#{bean.orderID}" />
<f:viewParam name="sortMode" value="#{bean.sortMode}" />
<f:viewParam name="firstRecord" value="#{bean.firstRecord}" />
<f:viewParam name="pageSize" value="#{bean.pageSize}" />
</f:metadata>
Each of those values is backed in the backing bean such that, if they are not set, they produce a suitable default value. For example:
public int getPageSize() {
if (pageSize < MIN_PAGE_SIZE) pageSize = DEF_PAGE_SIZE;
if (pageSize > MAX_PAGE_SIZE) pageSize = DEF_PAGE_SIZE;
return pageSize;
}
A link to this view can be generated as follows:
Now you implement user controls to change those values, and regenerate the table each time they are changed. You should still use AJAX for that -- for example:
<p:spinner value=#{bean.pageSize} >
<p:ajax update="tableID" />
</p:spinner>
In the setter methods, you have to trigger the re-generation of the table, but that's the gist of it. I hope this helps.
UPDATE:
To handle pagination, you simply need to add links for first page, prior page, next page, etc. The links will look something like this:
<h:link value="First Page" outcome="thisPage">
<f:param name="orderID" value="#{bean.orderID}" />
<f:param name="sortMode" value="#{bean.sortMode}" />
<f:param name="firstRecord" value="0" />
<f:param name="pageSize" value="#{bean.pageSize}" />
</h:link>
<h:link value="Next Page" outcome="thisPage">
<f:param name="orderID" value="#{bean.orderID}" />
<f:param name="sortMode" value="#{bean.sortMode}" />
<f:param name="firstRecord" value="#{bean.nextRecord}" />
<f:param name="pageSize" value="#{bean.pageSize}" />
</h:link>
etc. You need to implement properties in the backing bean to calculate what the firstRecord param ought to be.

Where are the pictures of my JSF page?

I have a navigation-rule like this in my JSF 2 application:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-action>#{myBean.goToMyHome1}</from-action>
<from-outcome>myHome1.xhtml</from-outcome>
<to-view-id>/myhome1/myHome1.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
When I put an h:commandLink in myHome2.xhtml within directory myhome2 that satisfy this rule, the page myHome1.xhtml will display but there are no images on the page. Where they go?
Behind the application is Springsecurity 3 with this config:
<sec:intercept-url pattern="/myhome1/**" access="hasAnyRole('ROLE1','ROLE2')" />
<sec:intercept-url pattern="/myhome2/**" access="hasRole('ROLE2')" />
This look like as if your picture URLs are relative to the current URL path. E.g.
<img src="images/picture.png" />
When you open the page by
http://example.com/contextname/myHome1.xhtml
then the image URL will effectively point to
http://example.com/contextname/images/picture.png
But when you open the page by
http://example.com/contextname/myhome/myHome1.xhtml
then the image URL will effectively point to
http://example.com/contextname/myhome/images/picture.png
You need to fix it accordingly. There are several ways. Use a domain-relative path
<img src="/contextname/images/picture.png" />
Or prepend the context name dynamically
<img src="#{request.contextPath}/images/picture.png" />
Or just use <h:graphicImage> which will do that automatically
<h:graphicImage value="/images/picture.png" />

Potential Primefaces Dialog Enter Submit Bug?

I have the exact same dialog form setup as the primefaces example below. When I put my cursor in the p:inputText on the below primefaces example and hit enter the window is closed automatically. On my example, I've even removed all links/buttons etc and just have a form and an input and it still closes the dialog when hitting enter. Any way around this?
http://www.primefaces.org/showcase/ui/dialogForm.jsf
mycode:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:dc="http://dc.dreamcatcher.com/facelet-taglib">
<ui:composition template="#{layoutBean.registeredTemplate}">
<ui:define name="content">
<h:form id="dreamModifyFrm">
<p:commandLink onclick="webSearchDlg.show();" value="open"/>
<p:dialog header="#{bundle['dreamSearch.HEADER']}"
widgetVar="webSearchDlg" modal="true" styleClass="dialog dialog2"
draggable="false" resizable="false" showEffect="fade" position="top"
hideEffect="fade">
<p:inputText id="searchText" value="#{dreamSearchBean.searchText}"/>
</p:dialog>
</h:form>
</ui:define>
</ui:composition>
</html>
My issues was fixed using the below:
There is a "feature" in IE where if you have only a single input element inside a form then hitting enter while focus in in the input element causes the form to submit (regardless of whether you even have a submit button). One way to prevent this is to add a second input element with style="display: none;".
Add the following onkeyup attrubute with a little JavaScript to the <h:form> or the <h:inputText> element to prevent the default action on enter press.
onkeyup="return event.keyCode != 13"
The enter key has a keycode of 13, so the above will return false when it is pressed and so the element's default action will be blocked.
Let me just wrap it up from a 2013 perspective:
When using newer PrimeFaces (3.2+?) versions, you can also use
<p:defaultCommand target="search-button" />
as described here:
http://blog.primefaces.org/?p=1787
ShowCase link:
http://www.primefaces.org/showcase-labs/ui/defaultCommand.jsf
Of course, this tag must be directly underneath the h:form tag, otherwise the tag isn't working.
When not using PrimeFaces, you must have something like
<h:inputText style="display: none;" />
on the form, as described in the earlier answer by c12.
Both of the above will cause IE browsers to behave like FF, Chrome, etc. When not using IE at all, BalusC's solution suffices.
I got the same Problem. I have a From with several Dozens InputTexts and several Buttons. When i pressed 'enter' in a inputText, the first Button was triggered and NOT the submit Button.
The hints above (onkeyup="return event.keyCode != 13" and p:commandButton with display:none) didn't work for me.
My solution was pretty simple and works. Just let your Submit-Button be the first button in your HTML-Code. The correct layout/arrangement of Button can be done via CSS, i.e. "float: left;"
Example:
<p:commandButton value="Save" ajax="true"
icon="ui-icon-disk"
update="myTable"
actionListener="#{myTableBean.save()}" />
<p:commandButton id="previousPeriod" update="myTable"
icon="ui-icon-triangle-1-w" ajax="true" type="push"
style="float: left;"
actionListener="#{myTableBean.scrollPrevious}"
value="Previous" />
After putting my Save-Button before my "Previous"-Button, everything worked fine! After pushing "enter" within a inputText, the Form gets submitted now and the "float:left" places the Prev-Button before the Save-Button in the visual Layout.

Resources