how to load page from hyperlink in JSF-2.2 [duplicate] - jsf-2

I've read how to send parameters using JSF but what if the user types their companyId in the URL when accessing their login page? For example,
http://my.company.url/productName/login.faces?companyId=acme.
The way we do it now, there is a bit of scriptlet code that grabs the value from the request and then set it in the session. That parameter changes their look and feel starting from the login page forward so each customer could have a different login page view. We are using extjs until I switch over to JSF.
Is there a way to do that using JSF 2 or perhaps PrimeFaces?

Yes, you can use the <f:viewParam> to set a request parameter as a managed bean property.
<f:metadata>
<f:viewParam name="companyId" value="#{bean.companyId}" />
</f:metadata>
You can if necessary invoke a bean action using <f:viewAction> (JSF 2.2+ only) or <f:event type="preRenderView">.
<f:metadata>
<f:viewParam name="companyId" value="#{bean.companyId}" />
<f:viewAction action="#{bean.onload}" />
</f:metadata>
When using <f:viewAction> you can even return a navigation outcome.
public String onload() {
// ...
return "somepage";
}
When not on JSF 2.2 yet, you can use ExternalContext#redirect() for that. See also among others How to perform navigation in preRenderView listener method.
Note that this is not specific to PrimeFaces. It's just part of standard JSF. PrimeFaces is merely a component library which provides enhanced ajax and skinnability support.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters
#ManagedProperty with request parameter not set in a #Named bean

url paramters can also be treated as request parameters so you can also access through
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()

There is a utility library, OmniFaces which does this out of the box.
#Inject #Param
private String key;
#Inject #Param
private Long id;

You can use the request.getQueryString() if you want to get full query parameter string.

Related

Update URL parameters after method call

This should be simple, but I am looking at other questions and I am not able to find the right answer for my issue.
I have a JSF page that calls a method myController.load():
<f:metadata>
<f:viewParam name="id" value="#{myController.id}" required="false"/>
<f:viewAction action="#{myController.load()}" />
This method will generate an id that is placed in myController.id if originally the page was not called with such parameter. My question is how can I make the URL at the navigation bar reflect this change, i.e. insert this new parameter in the URL. Basically:
--> Browse to myPage.xhtml
--> call to myController.load() which sets myController.id = 1
--> Reflect in URL myPage.xhtml?id=1. Ideally without re-loading the page
You will want to do some reading about PRG (Post/Redirect/Get). Here is a good start.
https://mobiarch.wordpress.com/2012/08/09/doing-post-redirect-get-pattern-in-jsf-2/
You'll want your original JSF link to call an ActionListener that will create a scoped reference to myController and set the id attribute to 1 there... then you can use PRG to redirect to your page. PRG will use the value of your bean to build the new URL correctly as you want.
This ActionListener method is very simple just to help illustrate...
// my ActionListener method
public String goToMyPage() {
myController.setId(1); // assuming myController is declared in scope.
return "myPage?faces-redirect=true&includeViewParams=true";
}
Hope this helps get you started.

jsf 2.2 enable disable button with EL and not javascript [duplicate]

I have an inputField, or some other tag , that I want to be disabled unitl user clicks on it.
Something like this, but I cant get it to work in JSF.
$("div").click(function (evt) {
$(this).hide().prev("input[disabled]").prop("disabled", false).focus();
});
I add disabled=true" to my input field, and div value set on < h:form > (all parent tags in this case only one), something like j_idt13 and div of input field, so "div" value looks like j_idt13:inputID
Can someone help me with jQuery solutin?
I wold like to know can it be done in JSF, and how.
You need to toggle it via server side, not via client side. JSF as being a stateful component based MVC framework safeguards this way against tampered/hacked requests wherein the enduser uses client side languages/tools like HTML or JS to manipulate the HTML DOM tree and/or HTTP request parameters in such way that the outcome of JSF's disabled, readonly or even rendered attribute is altered.
Imagine what would happen if the JSF developer checked an user's role in such a boolean attribute against the admin role like so disabled="#{not user.hasRole('ADMIN')}" and a hacker manipulated it in such way that it isn't disabled anymore for non-admin users. That's exactly why you can only change the mentioned attributes (and the required attribute and all converters, validators, event listeners, etc) via the server side.
You can use <f:ajax> in any ClientBehaviorHolder component to achieve the requirement. You can let JSF generate a HTML <div> via <h:panelGroup layout="block">, which is also a ClientBehaviorHolder:
<h:form>
<h:panelGroup layout="block">
Click this div to toggle the input.
<f:ajax event="click" listener="#{bean.toggle}" render="input" />
</h:panelGroup>
<h:inputText id="input" ... disabled="#{not bean.enabled}" />
</h:form>
With this #ViewScoped managed bean (#RequestScoped wouldn't work for reasons mentioned in #5 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated):
#Named
#ViewScoped
public class Bean implements Serializable {
private boolean enabled;
public void toggle() {
enabled = !enabled;
}
public boolean isEnabled() {
return enabled;
}
}
See also:
What is the need of JSF, when UI can be achieved from CSS, HTML, JavaScript, jQuery?
Why JSF saves the state of UI components on server?
Unrelated to the concrete problem, head to the following answers in case you're actually interested in how to obtain the HTML representation of JSF components via JS/jQuery:
How to select JSF components using jQuery?
How can I know the id of a JSF component so I can use in Javascript

How to get a POST request parameter with a bean managed by CDI?

With requestscoped beans managed by JSF (#Managedbean) you can get the value of a request parameter with #ManagedProperty("#{param.id}").
If the request is a GET request, you can get the value of a request parameter with f:viewParam.
Is there a special mechanism to get the value of a request parameter when the bean is CDI managed (#Named) and the request is a POST request? I only know the Java code
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
The <f:viewParam> works as good in POST requests.
You should only keep in mind that this runs during apply request values phase only, not during render response phase. So, if you're actually navigating on an action method and expecting the parameter to be set as view parameter of the target page, then you're wrong. It will only be set on the view where the POST request is actually submitting to.
As an evidence that the <f:viewParam> works on POST as well, here's a test snippet:
<f:metadata>
<f:viewParam name="foo" />
</f:metadata>
<h:form>
<h:commandButton value="submit">
<f:param name="foo" value="bar" />
</h:commandButton>
</h:form>
<p>foo: #{foo}</p>
Pressing the submit button will show up foo: bar.
You need to solve your concrete functional requirement in a different manner. As you didn't tell anything about the concrete functional requirement in your question, it's not possible to give an elaborate answer on that. Here are at least some hints:
#Inject target bean and set it as property during action method.
Use <f:setPropertyActionListener>.
Use flash scope.
Send a redirect with parameter in query string.

evaluate jsf bean property based on URL

Is there a way to display a specific JSF page based on the request URL?
Let's say I have a JSF page "details.xhtml". The managed bean "detailsBean" has a list of objects where each object has its own ID. Now if a user requests the page "../details.xhtml?id=1", the list should be queried for an object with ID 1 and the resulting details page of this object should be displayed.
I already wrote a converter implementation class which can convert from object to ID and vice versa, but I don't know how to use it properly. Do I have to work through the JAX-RS specification for this to work or is there a more simple solution?
In JSF you can do this by using a so-called view parameter. You declare these in the metadata section of your Facelet:
<f:metadata>
<f:viewParam name="id" value="#{yourBean.yourObject}" label="id"
converter="yourObjectConverter"
/>
</f:metadata>
This will grab the URL parameter id from the request URL. E.g. if you request the page this appears on with localhost:8080/mypage.jsf?id=1, then 1 will be handed to the yourObjectConverter and whatever this converter returns will be set in yourBean.yourObject.
Your backing bean will thus get the converted object. No need to pollute your backing bean over and over again with the same query code.
#ManagedBean
public class YourBean {
private SomeObject someObject;
public void setYourObject(SomeObject someObject) {
this.someObject = someObject;
}
}
If your backing bean is view scoped, you may want to use the OmniFaces variant of viewParam instead, since otherwise it will needlessly convert after each postback (if your converter does a DB query, you definitely don't want this).
Working full examples:
http://code.google.com/p/javaee6-crud-example/source/browse/WebContent/user_edit.xhtml
http://code.google.com/p/javaee6-crud-example/source/browse/src/backing/UserEdit.java
Further reading:
Communication in JSF 2.0 - Processing GET request parameters
Stateless vs Stateful JSF view parameters
You can achieve this with plain JSF with the following steps
Capture the ID in the request to determine what object is being queried for in your DetailsBean from the request parameter. There are many ways to achieve this, one of which is adding the following annotation to your managed bean (this is currently only permitted for a #RequestScoped bean, see why here).
#ManagedProperty(value="#{param.id}")
int requiredObjectId;
The annotation above will capture the id parameter from the request and assign it to the requiredObjectId variable.
Using the captured Id, setup your object in your bean in a #PostConstruct method
#PostConstruct
public void queryForObject(){
//use the requiredObjectId variable to query and setup the object in the backing bean
}
The object retrieved should be assigned as an instance variable of your managed bean
In your view, you could then reference the queried object that has been setup in the backing bean
<h:panelGrid columns="2">
<h:outputText value="Title"/>
<h:outputText value="#{detailsBean.selectedObject.title}"/>
</h:panelGrid>
If your bean is in a scope broader than the request scope, you'll need a combination of constructs to cleanly pull that request parameter before view rendering.
Capture the request parameter within the JSF view itself using
<f:metadata>
<f:viewParam name="id" value="#{detailsBean.requiredObjectId}" required="true" requiredMessage="You must provide an Object Id"/>
</f:metadata>
**OR**
Due to the nature of JSF Lifecycle processing, doing the above alone may not make the value available for your use in time for object setup. You could use the following instead.
<f:metadata>
<f:event type="preRenderView" listener="#{detailsBean.setObjectId}" />
</f:metadata>
What we've done here is specify a method (that captures the id) in the backing bean that must be executed before the view is rendered, ensuring that the id parameter is available as at the time you need it. Proceed with step 3, only if you're using <f:event/> above.
In the backing bean, you now define the setObjectId method
public void setObjectId(){
Map<String,String> requestParams = FacesContext.getExternalContext().getRequestParameterMap();
requiredObjectId = Integer.parseInt(requestParams.get("id"));
}
Note that the above option is generally a work around/hack and not a clean solution as such

Is there any way to have a bean in ViewScope and RequestScope at same time

I have a table of Items, and in each row there is a link that forwards to the edit item page. To load data in the edit page I need the managed bean in request scope (if I put it in view scope I loose data in the forward).
To use ajax in the edit page I need the managed bean in view Scope due to some values I must keep. If I were working with JSF 1.0 and RichFaces I would do it with request scope and a4j:keepalive.
How do I get this funcionality with PrimeFaces and JSF 2.0 or how can I redefine the interface to get this?
Ok, finally based on the post below this is what worked for me:
CommandButton in the Items table:
<o:commandButton id="editButton"
action="#{itemTableMB.editItem(item.id)}" styleClass="botonTabla">
<h:graphicImage styleClass="imagenBotonTabla" url="/resources/images/icons/pencil.png"/>
</o:commandButton>
Action in the managed bean:
public String editItem(Integer id){
return "/pages/items/edit.xhtml?faces-redirect=true&id="+id;
}
edit.xhtml:
<f:metadata>
<f:viewParam id="id" name="id" value="#{itemMB.item.id}" required="true">
</f:viewParam>
<f:event type="preRenderView" listener="#{itemMB.loadItem}" />
</f:metadata>
Listener in itemMB:
public void loadItem(){
this.item = this.itemManager.get(this.item.getId());
}
To load data in the edit page I need the managed bean in Request scope (If I put it in view scope I loose data in the forward).
Are you using a navigation rule (or implicit navigation) without a redirect?
One solution would be to put backing beans of both the "table of items"-page and the "edit item"-page in view scope, and then go from the first to the second one directly via a GET request (e.g. using <h:link>) or a POST/redirect with a request parameter representing the row on which the user clicked.
Use <f:viewParam> on the second page to conveniently convert the request parameter back to an entity representing the item being edited.
If you were indeed using navigation without redirect, then this has the additional benefit that you won't suffer from the notorious 'one-URL-behind-problem', which can be rather confusing to users of your application and be a nightmare for support.

Resources