how to redirect from a jsf facelet if an el expression is true? - jsf

I have a jsf facelet which displays a summary of a search process.
Now I want to redirect to a detail page, if only one element was found by the search engine. I do not want to implement this redirect in my beans because I want to have the "knowledge" about this redirection out of my java code.
So I want to write something like that:
<ui:redirect if="#{searchResult.count eq 1}" target="details.jsf">
<f:param name="id" value="#{searchResult.firstResult.technicalId}" />
</ui:redirect>
Any solutions or ideas for that?
I know, there are page-actions in JSF 2.2 but I am using JEE6 and there is JSF 2.0 available.
Btw. I currently I am usingMyFaces, Primefaces and Richfaces.
Greetings.

You should do this job in the controller, not in the view.
To get search results, you first need to invoke an action method by a search form, right? Just do the redirect job right there. You can tell JSF to send a redirect by specifying the faces-redirect=true in the query string of the action outcome.
public String search() {
results = service.find(query);
if (results.size() == 1) {
return "details?faces-redirect=true&id=" + results.get(0).getTechnicalId();
}
else {
return "results";
}
}
Or if it's a GET request which is handled by <f:event type="preRenderView">, then do so:
public void onPreRenderViewListener() {
results = service.find(query);
if (results.size() == 1) {
FacesContext.getCurrentInstance().getExternalContext().redirect("details.jsf?id=" + results.get(0).getTechnicalId());
}
}

I would say the cleanest way is to generate the action in the bean.
Anyway I would propose you to simulate a click in case your search count is eq to 1 with javascript.
you need an input hidden containing the count:
<h:inputHidden id="count" value="#{searchResult.count}" />
and a hidden button to trigger the redirection:
<h:commandButton id="redirectButton" action="details.jsf" style="display: none;" />
then when you trigger the search, you update the input count and oncomplete you can check
if the value of count is 1, then you can do a click on the commandButton.
If you use Jquery, it would be something like
if($("#count").val()==1){
$("#redirectButton").click();
}

Related

p:button with onclick javascript hook

I'm using p:button with onclick action. (I can't move to p:commandButton, because of legacy outcome navigation in faces-config.xml and custom navigation history in db):
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
Generated by primefaces javascript looks like
onclick="unlock_tt(); window.open(....)"
And after clicking button, unlock_tt() in browser initiated, but immediatly broken by page redirecting, so backed java method didn't execute.
Should I make unlock_tt() or java call async to be sure it will be executed before browser leaves page?
Upd: I'm thinking to use p:commandButton, if it is possible to get to-view-id programically, like in this question:
Programmatically get navigation case <to-view-id> from faces-config.xml by outcome
<p:commandButton action="#{ttEntityBean.unlock()}"/>
public String unlock() {
//some business logic
return OutcomeResolverHelper.getRuleFor(navigationMenuItemToRedirect.navigationRule)
}
This should reduce number of requests
I'm not sure this will work but can you try this :
Instead of :
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
do:
<h:panelGroup>
<f:ajax event="click" listener="#{ttEntityMBean.unlock}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" />
<h:panelGroup>
Don't forget to remove onclick and your remotecommand.
This should wrap a panelGroup around your button. PanelGroup implements ClientBehaviorHolder so it can get f:ajax tag in its children. Thus when you click on it it should trigger the listener.
The easiest way was migration from p:button to p:commandButton, which allows to execute some java-code in action method before redirect. The core is programmical translation of navigation rule, defined in faces-config.xml to base url, usable in explisit jsf-2.0 style:
//receive base url from <to-view-id> tag
public static String resolveOutcomeRule(String ruleName) {
FacesContext context = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler configNavHandler = (ConfigurableNavigationHandler)context.getApplication().getNavigationHandler();
NavigationCase navCase = configNavHandler.getNavigationCase(context, null, ruleName);
return navCase.getToViewId(context);
}
//decorate it with faces-redirect=true and our custom navigation
public static String resolveOutcome(NavigationMenuItem item) {
return resolveOutcomeRule(item.getNavigationRule()) + "?faces-redirect=true&menu=" + item.getId();
}
//controller-method
public String cancelEditTT() {
super.unlock();
return FacesUtil.resolveOutcome(getNavigationMenuItemToRedirect());
}
//new jsf button:
<p:commandButton value="#{msgs['button.ok']}" action="#{ttEntityMBean.cancelEditTT}"/>
This solution provided 1-step redirect instead of 2-step old one.

JSF PrimeFaces rendering components

Let's say I have a simple method that, like this:
public String test()
{
return "hello";
}
Now let's say I have the following PrimeFace component:
<p:fieldset styleClass="containers" rendered="#{controller.test()}">
<h2>Testing</h2>
<p:outputLabel for="test" value="Test" />
<p:inputText id="test" />
</p:fieldset>
The method above returns "hello". I would like to dynamically show and hide that fieldSet by comparing the returned value of that method to a field of one of my beans. For instance, on the rendered parameter, I would like to do something like: controller.test() != "some variable" which would return true or false. Am I allow to do that? If not, what is the way of doing it?
Basically the goal is to dynamically show and hide some container by comparing the returned value of a method with a bean property.
Look Like you misunderstood rendered
The rendered Attribute
A component tag uses a Boolean EL expression, along with the rendered
attribute, to determine whether or not the component will be rendered.
If you will check above definition you will know what exactly is the use of this attribute.
More you can see below
The rendered attribute which uses Boolean EL expression indicates
whether a component is currently visible or not. The property is
useful when you want to hide components for specific users or based on
condition. The default value of rendered attribute is true.
<h:outputText value=”mapping” rendered=”Boolean EL expression” />
For example, the commandLink component in the following section of a page is not rendered if the cart contains no items:
<h:commandLink id="check"
...
rendered="#{cart.numberOfItems > 0}">
<h:outputText
value="#{bundle.CartCheck}"/>
</h:commandLink>
With your concrete problem you can do like this
Make a String variable call value
Now create get/set methods for above variable
Now in your test method you can add
public void test(){
value="hello";
}
Bur remember you have call test() method of page load
Now in your Xhtml or Jsf or Jsp page
rendered="#{controller.value != 'hello'}"
Or better way create a Boolean variable and do all the magic of hide and show the component

Redirect my page after h:commandLink action in JSF [duplicate]

This question already has answers here:
Creating master-detail pages for entities, how to link them and which bean scope to choose
(2 answers)
Closed 7 years ago.
I have two pages:
listMedicalJourneys.xhtml
listAffectedEmployees.xhtml
From the first page:
<h:form>
<h:commandLink action="#{MedicalJourneyController.listAffectedEmployees()}" value="Manage">
<f:setPropertyActionListener value="#{element.id}" target="#{MedicalJourneyController.medicalJourneyId}" />
</h:commandLink>
</h:form>
The #RequestScoped bean #{MedicalJourneyController} has this method:
public String listAffectedEmployees() {
MedicalJourney m = medicalJourneyBean.getMedicalJourneyById(medicalJourneyId);
setMesList(new ArrayList<MedicalJourneyEmployeeService>(m.getMedicalJourneyEmployeeServices()));
setSelectedMedicalJourney(m);
return "listAffectedEmployees.faces?faces-redirect=true";
}
When I use the redirect to change URL, the next page doesn't show the selected value.
if i understand you right, you want to select an item inside one view, and display its SubItems in the next View. if this is the Case then, there are seviral ways to acheave this, here i will show you a way based on your Concept/Code above, so lets assume the following:
listMedicalJourneys.xhtml the View where you select an Item
listAffectedEmployees.xhtml the view Where you display SubItems of the preselected Item
and i assume that you have for each View its own Controller/ManagedBean,
so lets call the first one medicalJourneysManager and for the second view affectedEmployeesManager, both are requestScoped Beans
in the medicalJourneysManager your "selection Methode" action event should only get the selected ItemId, and pass this selected id to the next Page. Next Page Controller should then load the List of SubItems. Because a requestScoped Bean is only available during this single request, and as soon as you navigate anywhere, your bean will be reinitialized, that means the loaded data is lost at this moment.
so in your medicalJourneysManager define some ActionMethode like this:
//JSF 2.+
public String selectMedicalJourny(int medicalJourneyId) {
// do what ever you want before redirect, i.e. any validations, ...etc if required
return "listAffectedEmployees.faces?faces-redirect=true&medicalJourneyId="+medicalJourneyId;
}
this will redirect you to the next View where you display a list of AffectedEmployees
this new View needs its Controller "affectedEmployeesManager" to load the list of affectedEmployees.
so in the this managed Bean do something like this:
#PostConstruct
private void init(){
try{
String medicalJourneyId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("medicalJourneyId");
// now do whatever you want with it, load its subNodes/affectedEmployeesList, ...etc
MedicalJourney m = medicalJourneyBean.getMedicalJourneyById(medicalJourneyId);
setMesList(new ArrayList<MedicalJourneyEmployeeService>(m.getMedicalJourneyEmployeeServices()));
setSelectedMedicalJourney(m);
}catch(Exception e){
e.printStackTrace();
}
}
a simpler alternative to commandLink is using a direct link with that param without any action commands.
here is a helpfull link.

jsf 2 outputlink rendering method call without clicking

I am relatively new in jsf.
I have a jsf page someDetails.xhtml, in which I have an output link
<h:outputLink value="#{someTaskController.completeTask(taskId)}?taskId=#{taskId}">Assign Ticket</h:outputLink>
On clicking on this link, the method completeTask should be called and do something.
The problem is, when the jsf page someDetails.xhtml is opened(in browser), the method completeTask is getting called and does all the task, which should only happen on clicking the link.
What should I do ? Please help
You're using the wrong tag for your purpose, use command link instead:
<h:commandLink value="Assign Ticket" action="#{someTaskController.completeTask()}">
<f:param name="taskId" value="#{taskId}" />
</h:commandLink>
You can access taskId inside method completeTask() like this:
public void completeTask() {
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String taskId= params.get("taskId");
// do your business action...
}

How to autosubmit a form in jsf

I am trying to autosubmit a jsf form.
I have one inputhidden textbox in the form, where the field value is set from request object.Once its done, the form need to submit automatically.
I have done autosubmit using javascript and also using Primefaces, but I need to do it using Simple JSF stuff.
No need of using richfaces, primefaces.
<h:form id="form">
<h:inputhidden value="#ManagedBean.user"/>
<h:comandbutton action="#{ManagedBean.processAction()}" /> //disabled
</h:form>
if you use jquery, you can add an event listener to the form and check if enter is pressed.
We do this following way with richfaces, but it maps quite simple to jquery:
<rich:hotKey
selector="#searchForm"
key="return"
type="keypress"
handler="if (isValidInputFieldForHotkeyEvent(event)) { event.preventDefault(); jQuery('.searchFormDefaultAction').click(); } else { sendShiftEnter(event); }"
disableInInput="false"
disableInInputTypes=""/>
These are the javascript functions:
function isValidInputFieldForHotkeyEvent(event) {
return event.target.type != 'textarea';
}
function sendShiftEnter(event) {
event.shiftKey = true;
event.ctrlKey = true;
event.altKey = true;
event.keyCode = 13;
event.target.fireEvent("keyPressed", event);
}
You can use plain old javascript? On window load call
document.getElementById('form').submit();

Resources