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
Related
We have a JSF application with <rich:tab> which shows fields depending of some configuration stored in a database, so the components are not defined in the .xhtml page but have to be generated programmatically such in this example:
Components are generated in a panel:
<rich:tab id="someTab" header="#{msg['someHeader']}" immediate="true">
<rich:messages/>
<h:panelGrid id="generatedComponentsContainer"/>
</rich:tab>
Component generation example (simplified for simplicity):
FacesContext ctx = FacesContext.getCurrentInstance();
UIPanel panel = (UIPanel) ctx.getViewRoot().findComponent("someForm:generatedComponentsContainer");
text = (UIInput) ctx.getApplication().createComponent(ctx, "javax.faces.Input", "javax.faces.component.UIInput");
text.getAttributes().put("label", someLabel);
panel.getChildren().add(text);
Those components have to be shown disabled depending on some condition, so I used the following code to disable each of them if needed:
if (!showEnabled) { text.getAttributes().put("disabled", "true"); }
This method works for UIInput and HtmlInputTextarea but it is not working for UICalendar, throwing a IllegalArgumentException (argument type mismatch).
How can I disable the calendar?
I have been also wondering if this code just disables the component at the client side leaving it enabled at the server. This would probably be a security threat as somebody could enable a component via Javascript and submit the form to the server. I am not sure about this being possible, please advise if I am wrong.
After further research I noticed there are some classes that extend the ones we were using in our project. Those classes have a getter/setter for the disabled attribute which also disables the component in the server side. I tested this disabling the components programmatically and removing the disabled attribute while browsing the page to allow edition and submit. When submitting the form, the values are setted in the request but ignored at the server side. Bean values remain unaltered.
The classes we have used:
HtmlInputTextarea instead of UIInput
HtmlInputText instead of UIInput
We were already using UICalendar, which fits the purpose
A sample of code:
HtmlInputText text = (HtmlInputText) ctx.getApplication().createComponent(
ctx, HtmlInputText.COMPONENT_TYPE, "javax.faces.component.html.HtmlInputText");
if (!showEnabled) { text.setDisabled(true); }
When debugging the contents of the HtmlInputText you can see a ComponentStateHelper object (named stateHelper) which stores the disabled state of the component (among other data). Its superinterface is StateHolder:
public interface StateHolder
This interface is implemented by classes that need to save their state
between requests.
I understand that server-side state of the component is stored in this object, but I am not sure whether it is stored only here or in more points, or even if my interpretation of its purpose is correct. Feedback from an expert would be very useful.
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.
During some tests made using JSF 2 (mojarra on Glassfish 3.1.1) I've faced with strange behavior I can't explain.
This is my managed bean:
#ManagedBean
#RequestScoped
public class TestBean {
private int id;
public void hideButton() {
id = 0;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Here is my xhtml page
<h:form>
<h:inputHidden value="#{testBean.id}"/>
<h:outputText value="#{testBean.id}"/>
<h:commandButton value="set 1"
actionListener="#{testBean.setId(1)}">
</h:commandButton>
<h:commandButton value="hide button"
action="#{testBean.hideButton}" rendered="#{testBean.id > 0}">
</h:commandButton>
</h:form>
I expected, the button "hide button" is not visible on initial load of the page and this is really the fact. After a click on the button "set 1", the button "hide button" appeares and that is also to expect.
Really not understandable thing to me is the fact the subsequent click on the button "hide button" does not invoke the method testBean.hideButton and set the id to 0.
I've read the very useful answer from BalusC (thanks a lot really) here
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
and recognize, the problem is related to the attribute "rendered", if I remove it, the action is invoked.
But as far as I aware, the class member must be initialized during the UPDATE MODEL VALUES phase and the condition mentioned in the attribute rendered should be evaluated to true during INVOKE APPLICATION phase and the action should be invoked.
The example works if I change the scope of the bean to View/Session.
But it also works fine if I remove the render attribute from the "hide button"
Would somebody explain such behavior?
In other words, at what phase the expression of the rendered attribute is evaluated to make decision not to invoke the action?
The rendered attribute is also evaluated during apply request values phase, at the moment when JSF needs to identify which action needs to be invoked. If it evaluates false, then the action can't be identified and will thus also not be invoked.
The problem is caused by the too narrow managed bean scope. As your managed bean is request scoped, it get trashed by end of response and recreated (with all properties set to default) on any subsequent request. The model value on which the rendered attribute depends will only be updated during update model values phase, which is too late. You should be placing the managed bean in view scope instead.
Apart from changing the bean scope to view scope, another way is to check the request parameter map value instead in the rendered attribute.
<h:form id="form">
<h:inputHidden id="id" ... />
<h:commandButton ... rendered="#{param['form:id'] gt 0}" />
</h:form>
(by the way your usage of > instead of gt indicates that you're using the deprecated JSP view technology instead of Facelets, I would strongly recommend to migrate to Facelets)
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
How to choose the right bean scope?
I've found myself the reason of the problem.
The method UIComponentBase.processDecodes (at the Apply Request Values phase) calls isRendered, which returns false, because it is before the Update Model Values. Which skips the decode of the component.
There are some workarounds possible, all of them imho are not cool, but nevertheless it works
It is possible manually to set necessary value in managed bean in (post)constructor from request parameters.
Or to use
I have a multi-page form, aka a Wizard pattern, where Page 1 corresponds to Step 1 of the wizard form, Page 2 corresponds to Step 2, etc. Each page other than the last has a Next button on it that takes you to the next page in the form. The final page has a submit button that submits all the data for all pages in the wizard.
What scope should I use to maintain the state of the data entered on each form? e.g. should I use a View Scoped bean that holds all the data entered on all pages? Will that work since I'll be navigating to different pages (Which I believe are considered to be different "views"; and if they're different views, I believe the View Scoped data will be lost when you navigate to the next page in the wizard)
I believe the View Scoped data will be lost when you navigate to the next page in the wizard)
That's correct. The view scope lives as long as you're interacting with the same view and get trashed whenever a new view get created. You're looking for the "conversation scope". This isn't available by any of the JSF managed bean scopes. This is however available by CDI #ConversationScoped. So if your environment happen to support CDI, you could make use of it:
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#ConversationScoped
public class Wizard implements Serializable {
#Inject
private Conversation conversation;
#PostConstruct
public void init() {
conversation.begin();
}
public void submitFirstStep() {
// ...
}
// ...
public String submitLastStep() {
// ...
conversation.end();
return "someOtherPage?faces-redirect=true";
}
// ...
}
The conversation is managed by the automatically inserted cid request parameter.
If you'd like to stick to the JSF view scope, then your best bet is to create a single page wherein you render the multiple steps conditionally:
<h:panelGroup rendered="#{wizard.step == 1}">
<ui:include src="/WEB-INF/wizard/step1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 2}">
<ui:include src="/WEB-INF/wizard/step2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 3}">
<ui:include src="/WEB-INF/wizard/step3.xhtml" />
</h:panelGroup>
Or, you could use a 3rd party component library like PrimeFaces which has a <p:wizard> component for exactly this purpose.
From my pov, good choice here is session scoped beans. When needed, user will be able to interrupt the wizard, visit other pages, doc, manuals, whatever, and get back to the same wizard step. Of course it can be done via view-scoped beans (see BalusC answer). Personally I prefer view-scoped beans when ajax is heavily involved. In that case I'd recommend to combine these two scopes.
You can find an example using the conversation scope for creating a wizard at this site:
JEE6 – CDI and Conversation Scope
My least favorite part of coding JSF 2.0 forms has to do with the handing of the id attributes of the various input elements. I am forever having trouble coding the clientID of the target component from within the backing bean, particularly since PrimeFaces tabView now includes the id of the p:tab element as part of the clientID. I waste tons of time coding, testing, then re-coding those clientIDs.
It is reminiscent of older-style assembly language programming where you have to generate tons of label names for your branches and loops. I've done of enough of that for a lifetime.
One approach I am trying is to use only auto-generated id attributes. For example one line of my form might look like this.
<h:outputLabel value="Full Name:" />
<p:inputText value="#{editUser.user.fullName}"
binding="#{editUser.compFullName}"/>
<p:message for="#{editUser.compFullName.clientId}" />
Note that I do not have an explicit id attribute. Then in the backing bean:
String clientID = getCompFullName().getClientId();
msg = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Summary Message For Full Name", "Detail Message Full Name");
FacesContext.getCurrentInstance().addMessage(clientID, msg);
This always works, even if the component has a complex clientID, such as when PrimeFaces inserts the p:tab id into the clientID. (Which it does starting v 3). Rearranging the form never breaks anything.
It is, however, laborious, since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?
since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?
It's not required to bind the component to some backing bean if you don't use it in there at all. Just bind it to the view instead:
<p:inputText value="#{editUser.user.fullName}"
binding="#{compFullName}"/>
<p:message for="#{compFullName.clientId}" />
To make the code more self-documenting, I suggest to put a HashMap in the request scope by faces-config.xml:
<managed-bean>
<description>Holder of all component bindings.</description>
<managed-bean-name>components</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
with
<p:inputText value="#{editUser.user.fullName}"
binding="#{components.fullName}"/>
<p:message for="#{components.fullName.clientId}" />
Adding messages is supposed to be done by a Converter or a Validator which is trowing it as a ConverterException or ValidatorException respectively. It will automatically end up in the right message holder. Or if it are informal messages, just add it on the client ID of the UIComponent which is already available as method argument.
See also:
JSF component binding without bean property