myfaces 2.1.17 - f:viewParam setter being called on commandlink [duplicate] - jsf

I'm using an <f:viewParam> to pass a parameter as follows.
<ui:define name="metaData">
<f:metadata>
<f:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
Is it possible to process this <f:viewParam>, only when the page is loaded/refreshed?
It is just because the converter as specified with the <f:viewParam> is costly that converts the value passed through the query-string to a JPA entity. Hence, it involves an expensive database transaction, even when doing ajaxical postbacks using components like <p:commandButton>, <p:commandLink> which is unnecessary.
So, when for example, a <p:commandLink> (ajaxical) is clicked, the expensive business service (in the converter) should not be executed. Can this be done?
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.

You can achieve this by creating a custom tag extending <f:viewParam> wherein you store the submitted value as an instance variable which isn't stored in JSF view state instead of in the JSF view state as the <f:viewParam> by default does. By end of request, all UI component instances are destroyed. They are recreated in beginning of the request. When submitted value is null, then it won't call the converter nor the model setter. This all is elaborated in Arjan Tijms' blog.
OmniFaces offers already since version 1.0 a ready to use solution in flavor of <o:viewParam>, see also my own blog on that. Based on your question history, you're already using OmniFaces, so all you basically need to do is to replace f: by o:.
<ui:define name="metaData">
<f:metadata>
<o:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
This won't call the model setter (nor the converter) during postbacks on the same view.
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
That's because the <f:viewParam> is in essence an UIInput component (else it wouldn't be able to perform conversion, validation, model-update and all that stuff like usual input components) which is thus just an UIComponent supporting a rendered attribute. This is however not explicitly documented as it actually doesn't render anything to the HTML output (that's also why it's a f:xxx, not a h:xxx). But with this attribute you can actually control the behavior during postback as this attribute is also evaluated in processDecodes() method which is invoked during apply request values phase.

Related

p:inputText with p:ajax calls f:viewParam Converter

We do have a small page which is using the viewParam to convert a given Id to a concrete object. This converter is called on leaving (blur) of an inputText field, which is validated. Why? Could I rework this, so that the converter is not called every time?
This is annoying, because the converter calls the set-method for the corresponding object in the BackingBean and this bean is then null, if the page is called the first time for creating this object.
<f:metadata>
<f:viewParam name="id" value="#{bean.object}"
converter="#{objectConverter}"
converterMessage="#{msgs['converter.msg.object']}"/>
<f:viewAction action="#{bean.init}"/>
</f:metadata>
<p:inputText id="text" value="#{cc.attrs.value}"
styleClass="inputTextValidated"
required="#{cc.attrs.required}"
requiredMessage="#{cc.attrs.requiredmessage}"
label="text" validatorMessage="#{cc.attrs.msg}" title="#cc.attrs.title}"
readonly="#{cc.attrs.readOnly}">
<cc:insertChildren/>
<p:ajax update="msg_text" event="blur"/>
</p:inputText>
<p>
<p:message id="msg_text" for="text" display="msg"/>
</p>
If we do not use a converter but just the viewAction to convert the Id to the corresponding object (or create a new object if applicable), everything is fine. Is this the only/correct solution for this problem?
We do use primefaces 6.1 with CDI. The converter is a #Named and #ApplicationScoped bean implementing the Converter Interface.
Using p:fragment around the inputtext-field did not help either.
That is the nature of how JSF works. If you want to not have it do that I suggest you check out OminFaces ViewParam: http://showcase.omnifaces.org/components/viewParam
From their documentation:
Stateless mode to avoid unnecessary conversion, validation and model
updating on postbacks The standard UIViewParameter implementation
calls the model setter again after postback. This is not always
desired when being bound to a view scoped bean and can lead to
performance problems when combined with an expensive converter. To
solve this, this component by default stores the submitted value as a
component property instead of in the model (and thus in the view state
in case the binding is to a view scoped bean).
The standard UIViewParameter implementation calls the converter and
validators again on postbacks. This is not always desired when you
have e.g. a required="true", but the parameter is not retained on form
submit. You would need to retain it on every single command
link/button by . To solve this, this component doesn't call
the converter and validators again on postbacks.

JSF: Passing bean to another JSF Page [duplicate]

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.

Process f:viewParam only on page load

I'm using an <f:viewParam> to pass a parameter as follows.
<ui:define name="metaData">
<f:metadata>
<f:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
Is it possible to process this <f:viewParam>, only when the page is loaded/refreshed?
It is just because the converter as specified with the <f:viewParam> is costly that converts the value passed through the query-string to a JPA entity. Hence, it involves an expensive database transaction, even when doing ajaxical postbacks using components like <p:commandButton>, <p:commandLink> which is unnecessary.
So, when for example, a <p:commandLink> (ajaxical) is clicked, the expensive business service (in the converter) should not be executed. Can this be done?
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
You can achieve this by creating a custom tag extending <f:viewParam> wherein you store the submitted value as an instance variable which isn't stored in JSF view state instead of in the JSF view state as the <f:viewParam> by default does. By end of request, all UI component instances are destroyed. They are recreated in beginning of the request. When submitted value is null, then it won't call the converter nor the model setter. This all is elaborated in Arjan Tijms' blog.
OmniFaces offers already since version 1.0 a ready to use solution in flavor of <o:viewParam>, see also my own blog on that. Based on your question history, you're already using OmniFaces, so all you basically need to do is to replace f: by o:.
<ui:define name="metaData">
<f:metadata>
<o:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
This won't call the model setter (nor the converter) during postbacks on the same view.
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
That's because the <f:viewParam> is in essence an UIInput component (else it wouldn't be able to perform conversion, validation, model-update and all that stuff like usual input components) which is thus just an UIComponent supporting a rendered attribute. This is however not explicitly documented as it actually doesn't render anything to the HTML output (that's also why it's a f:xxx, not a h:xxx). But with this attribute you can actually control the behavior during postback as this attribute is also evaluated in processDecodes() method which is invoked during apply request values phase.

What is the difference between <f:viewParam> and <f:param>?

What is the difference between <f:viewParam> and <f:param> in JSF 2.1?
Simply put:
<f:viewParam> is used inside <f:metadata> to attach an UIViewParameter as metadata for the current view. For example, if you access the page myapp/check.jsf?id=3 and your check.jsf page has this:
<f:metadata>
<f:viewParam name="id" value="#{mrBean.id}"/>
</f:metadata>
The value 3 will be set on mrBean's id property when the page is loaded.
On the other hand, <f:param> sets a parameter in the parent (enclosing) component of this tag, accessible later by obtaining the component's parameters themselves. This is in particular really powerful (yet, disastrous if used wrong) because through EL you can achieve some interesting results.
It can be used in different contexts. This link provides an interesting range of applications.

Does it matter whether place f:event inside f:metadata or not?

w.r.t. How to execute action on GET request with f:viewParam?
<f:metadata>
<f:viewParam name="id" value="#{tInputBean.id}" />
<f:event type="preRenderView" listener="#{tInputBean.init}" />
</f:metadata>
I'm interested to know whether it matters if a preRenderView f:event is placed inside the f:metadata or not. I've checked the Java EE6 tutorial, Java Server Faces 2.0 Complete Reference, and Core JSF2, and none of them have examples of f:event inside f:metadata, but I've seen lots of examples online like this.
JSF2 Compl.Ref says p.540
The f:metadata tag encapsulates the set of elements used to specify
the metadata for a Facelet view, and therefore must be a child of the
f:view tag and may not appear in a template. As of JSF2.0, the only
purpose of this tag is to encapsulate f:viewParam tags.
Does placing the f:event (often used to support an f:viewParam) inside the f:metadata have a special meaning, or is it just to help group it alongside the f:viewParam visually/logically ?
No, the <f:event> is not strictly required to be placed inside <f:metadata>. It can be attached to any component. It's indeed for pure self-documentary purposes placed inside the <f:metadata> whenever you have a bunch of <f:viewParam>s and would like to hook a <f:event> to invoke an action after all those view parameters have been set. It can even be placed outside/before those <f:viewParam>s, but it makes the code not more self-documenting.
Note that in the upcoming JSF 2.2, a new <f:viewAction> tag will be introduced which in turn is supposed to replace the <f:event type="preRenderView"> in the <f:metadata>.

Resources