This question already has an answer here:
How to disable/enable JSF input field in JavaScript?
(1 answer)
Closed 3 years ago.
I'm developing a Java EE application (JSF2 + richfaces 3.3.3 + facelets).
I want to disable my h:selectOneMenu when loading my page, and when it finishes loading (using the function onload()), I want to re-enable my component.
I have something like this:
<ui:define name="infosHead">
<script type="text/javascript">
window.onload = function() {
document.getElementById("forme1_myform:valueCh").disabled = false;
alert("here");
}
</script>
</ui:define>
<ui:define name="infosBody">
<h:form id="forme1_myform" target="_blank">
<h:selectOneMenu id="valueCh" value="#{mybean.value}" disabled="true" >
<f:selectItems value="#{mybean.values}" />
<a4j:support event="onchange"
ajaxSingle="true"
limitToList="true"
reRender="id1,id2,...."
ignoreDupResponses="true"
action="#{mybean.actionme}"
oncomplete="getId();"/>
</h:selectOneMenu>
</h:form>
</ui:define>
this is working fine.
But my bean is getting nothing (mybean.value == null).
It's like he thinks that the component is still disabled.
how can I make this works ?
The problem is that you are enabling your component only on the client side. On the server side it will always be disabled="true". To make this work you must :
a. Assign the disabled property of your component to a managed bean property that will be initially 'true'
disabled="#{myController.valueChDisableStatus}"
b. Inside your h:form insert window.onload = callScript
c. Finally, in the myController#someAction method set the valueChDisableStatus property to false
I cant check the solution right now, but I believe it will work fine.
I found this solution.
<ui:define name="infosHead">
<script type="text/javascript">
window.onload = function() {
updateName(false); // sets 'disabled' from true to false
}
</script>
</ui:define>
<ui:define name="infosBody">
<h:form id="forme1_myform" target="_blank">
<h:selectOneMenu id="valueCh" value="#{mybean.value}" disabled="#{mybean.render}" >
<f:selectItems value="#{mybean.values}" />
<a4j:support event="onchange"
ajaxSingle="true"
limitToList="true"
reRender="id1,id2,...."
ignoreDupResponses="true"
action="#{mybean.actionme}"
oncomplete="getId();"/>
</h:selectOneMenu>
</h:form>
<a4j:form>
<!-- this is where it's going to reRender my component -->
<a4j:jsFunction name="updateName" reRender="valueCh">
<a4j:actionparam name="param1" assignTo="#{mybean.render}" />
</a4j:jsFunction>
</a4j:form>
</ui:define>
and this is the content of mybean:
public class MyBean implements Serializable {
private List<SelectItem> values;
private String value;
private Boolean render = true; // the page loads with element disabled
public void actionme(){...}
//getters & setters
}
Neither of these solutions worked for me.
While setting the element's disabled attribute from a managed bean value worked fine, and changing it's value via javascript also worked fine, once the form is submitted the "someaction" method is still not reached in order to "set the valueChDisableStatus property to false". In addition I found that even though my managed bean had an isDisabled() and a setDisabled(boolean value), the setDisabled() method was never called after submitting the form (of course), though the isDisabled() was. So I was unable to find a way using these solutions to change the managed beans "disabledElement" value to false.
I did find a solution that did work for me though at this link:
http://blog.michaelscepaniak.com/jsf-you-cant-submit-a-disabled-form-element
Basically it suggests that by default all the elements should be "enabled" from the JSF perspective, and that all enabling and disabling should be done via Javascript. It does point out the the client and server states are out of sync temporarily in this solution... but it works very well for my scenario regardless of the temporary mismatch.
Related
I'm working with primefaces 4.0 and JSF 2.2 and I'm currently trying to update a form with a p:tree on it. The commandButton works correctly but it does not update the form or call the init() method until I manually refresh the page. I don't know what I'm doing wrong since the same code does work for a DataTable element.
Here's the code:
<h:form id="preferenciasForm">
<div id="panelTree">
<p:panel id="defTree" style="margin-bottom: 20px">
<p:tree value="#{dtPreferencesBuilder.root}" var="node"
selectionMode="checkbox"
selection="#{dtPreferencesBuilder.selectedNodes}"
style="width:100%; height:100%;" animate="true">
<p:treeNode>
<h:outputText value="#{node.label}" />
</p:treeNode>
</p:tree>
<p:commandButton value="Add preferences"
icon="ui-icon-pencil"
actionListener="#{dtPreferencesBuilder.insertPrefNodes()}"
update=":preferenciasForm" ajax="true" />
</p:panel>
</div>
</h:form>
And here's is the java class.
#ManagedBean(name="dtPreferencesBuilder")
#ViewScoped //I've tried with or without the ViewScoped, neither work
public class PreferencesBuilderBean {
private TreeNode root;
private TreeNode prefRoot;
private TreeNode[] selectedNodes;
#PostConstruct
public void init() {
System.out.println("Building Tree");
selectedNodes=null;
root=null;
prefRoot=null;
root=getStandardTree();
prefRoot=getPreferedTree();
}
The init() is not called as the print is only show on manual reload so the tree is not updated nor the selectedNodes refreshed. Any ideas why it doesn't work?
As I cannot describe bean scopes better than excellent answers already given for similar questions I'll just refer you to the answers by BalusC and Kishor P here.
The init-method (or any method with the #PostConstruct-annotation) will be called by the framework only when the bean is created, after injections and therefore after the constructor has run as rion18 said. It would not be normal to use the method for anything else than initializing work. So create other methods, and call those from actions and actionListeners.
If you want the bean to be the same when you call it with ajax (as you do) it needs to be at least ViewScoped. If you really do want to call the init() every time it should be RequestScoped, but then the bean will be new when you call it with ajax and not remember a thing.
Okay, so I have read through stackoverflow and various other portions of the net for a few days, and have not found a solution yet that fixes my issue.
Basically, I have an h:form in a p:dialog with two required fields. When the fields are both filled in, the form successfully submits and the dialog closes. When either or both fields are left blank, required field validation fails and updates the h:messages component in the p:dialog with the appropriate required messages. However, also when validation fails, the AJAX call seems to never "finish" and prevents subsequent calls from being executed. This is seen evident by my p:ajaxStatus component never disappearing from the screen, indicating that something is hanging somewhere. This is remedied by refreshing the page, at which point all other AJAX components begin to function again.
Additionally, I will note that this p:dialog is in a ui:define in a ui:composition, that dumps it into a master template. It is not nested within another h:form.
<p:dialog id="dlgDecision"
header="Decision"
widgetVar="dialogDecision"
modal="false"
resizable="false"
appendToBody="true">
<h:form id="fDlgDecision">
<h:messages id="msgDlgDecision" binding="#{msgform.messages}" errorClass="errormsg" infoClass="infomsg1" layout="table"/>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'A'}">
<h:outputText value="Select an accept and admit code."/>
</h:outputFormat>
<h:outputFormat rendered="#{studentdetailsform.decisionAction == 'C'}">
<h:outputText value="Select a cancel and reason code."/>
</h:outputFormat>
<h:panelGrid columns="1">
<h:selectOneMenu id="apdcCode"
value="#{studentDetails.apdcCode}"
required="true"
requiredMessage="Please choose a decision code.">
<f:selectItem itemLabel="Select Decision Code"/>
<f:selectItems value="#{apdcCodes.apdcCodeList}"
var="apdc"
itemValue="#{apdc.apdcCode}"
itemLabel="#{apdc.apdcCode} - #{apdc.apdcDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="admtCode"
value="#{studentDetails.admtCode}"
required="#{studentdetailsform.decisionAction == 'A'}"
requiredMessage="Please choose an admit code."
rendered="#{studentdetailsform.decisionAction == 'A'}">
<f:selectItem itemLabel="Select Admit Code"/>
<f:selectItems value="#{admtCodes.admtCodeList}"
var="admt"
itemValue="#{admt.admtCode}}"
itemLabel="#{admt.admtCode} - #{admt.admtDesc}"/>
</h:selectOneMenu>
<h:selectOneMenu id="wrsnCode"
value="#{studentDetails.wrsnCode}"
required="#{studentdetailsform.decisionAction == 'C'}"
requiredMessage="Please choose a reason code."
rendered="#{studentdetailsform.decisionAction == 'C'}">
<f:selectItem itemLabel="Select Reason Code"/>
<f:selectItems value="#{wrsnCodes.wrsnCodeList}"
var="wrsn"
itemValue="#{wrsn.wrsnCode}"
itemLabel="#{wrsn.wrsnCode} - #{wrsn.wrsnDesc}"/>
</h:selectOneMenu>
<p:commandButton id="decisionSubmit"
value="Submit Decision"
type="submit"
action="#{mainform.saveDecision}"
ajax="true"
partialSubmit="true"
process="#form"
update="#form msgDlgDecision"
oncomplete="if (!args.validationFailed) dialogDecision.hide()"/>
</h:panelGrid>
</h:form>
</p:dialog>
Some things I have already done in my debugging and troubleshooting:
- Moved the h:form into the p:dialog
- Made the backing bean with the values for the rendered attribute on the required fields ViewScoped (was having an issue with only some of the required messages showing, this resolved this problem)
- Added appendToBody="true" to p:dialog
- Added if (!args.validationFailed) to the oncomplete event of p:dialog
- Tried making the required fields NOT conditional (removed rendered attributes) to be sure this wasn't being caused by failed validation on non-rendered components (grasping at straws...)
EDIT: Here is a console dump from Chrome. Javascript error gets thrown when submitting the form with null required fields.
Uncaught SyntaxError: Unexpected token { jquery.js:14
bG.extend.parseJSON jquery.js:14
PrimeFaces.ajax.AjaxUtils.handleResponse primefaces.js:1
PrimeFaces.ajax.AjaxResponse primefaces.js:1
j.success primefaces.js:1
bZ jquery.js:14
b7.fireWith jquery.js:14
ca jquery.js:21
bZ
EDIT 2: Below are the only two JavaScript imports, both of which are in my template that is applied to the page via the ui:define and ui:composition mentioned above.
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<script type="text/javascript" src="#{request.contextPath}/resources/scripts/jscript.js" />
The first import will force Primefaces to import jQuery into the page, even if there are no components on the page that utilize JavaScript. This is to allow my custom scripts in jscript.js to use jQuery reliably.
Other information:
JSF 2.1
Primefaces 3.4.2
Tomcat 6.0
Don't import jQuery.js manually as this is already done implicitly by PrimeFaces (it uses jQuery under the hood). You can remove that line.
Also you should see some examples of importing your custom js files with h:outputScript like this for example:
<h:outputScript library="scripts" name="jscript.js" />
but this is probably not reason of your problem, this is just hint for better JSF design.
A similar error showed up in Google Chrome, today, after I downloaded PrimeFaces 4.0 snapshot (2013-05-09) and tested my app.
Basically, I had to remove single quotes from data sent from bean to p:schedule via JSON. Since the error mentioned 'parse JSON' and "unexpected '" (unexpected single quote), I went to the datatable view of my data (instead of p:schedule) and recognized that some of the data had single quotes embedded. So, I removed the single quotes from the data, and that solved the issue for me.
Please click forum topic URL below.
PF 4.0 SNAPSHOT 2013-05-09: schedule not working
I've had the exact same problem at my application. The real problem was a duplicate jar problem.
I've had two primefaces jar in my application, one under the WEB-INF/lib directory, and the other under the ear/lib directory. Once I deleted the one under the WEB-INF, everything started to work as expected.
You could find the solution on the net via a search for the js exception.
Just would like to know why do I encounter this behavior in my application.
I used primefaces for the UI and almost all of my pages follows this pattern. I heavily used AJAX in all of my CRUD
operations and using dialogs to show it to the user.
<ui:composition template="myTemplate.xhtml">
<ui:define name="content">
<ui:include
src="/pages/CreateDialog.xhtml" />
<ui:include
src="/pages/UpdateDialog.xhtml" />
<ui:include
src="/pages/DeleteDialog.xhtml" />
</ui:define>
</ui:composition>
My only concern is that, after doing CRUD stuff in my dialogs and user accidentally clicks F5 or refresh on the browser,
FF/Chrome and other browser always mentioned
To display this page, Firefox must send repeat action...
Obviously this will cause double submit. Previously I used Post-Redirect-Get in this scenario in older apps but since this
is AJAX JSF update then I cannot do this.
What's the workaround for this and is this normal? I thought AJAX actions should not trigger again during browser refresh.
Help?
UPDATE
I am opening my dialog with this code
<p:commandButton value="Add"
onclick="createWidget.show();"
update=":CreateForm"
action="#{MyBean.add}"
/>
My create dialog uses this
<p:dialog header="Create">
<h:form id="CreateForm" prependId="false">
<p:commandButton value="Add" icon="ui-icon-plus"
actionListener="#{MyBean.add}"
update=":messageGrowl"
oncomplete="closeDialogIfSucess(xhr, status, args, createWidget 'createDialogId')"/>
</h:form>
</p:dialog>
I actually am following the pages from this site...Full WebApplication JSF EJB JPA JAAS
Already experienced a few times that having JavaScript errors in callback methods ends up in such behavior. I was able to reproduce your problem which is disappeared after correcting the callback signature:
oncomplete="closeDialogIfSucess(xhr, status, args, createWidget, 'createDialogId')"
accordingly to you JavaScript function signature:
function closeDialogIfSucess(xhr, status, args, createWidget, dialogid)
(Sure if your JavaScript call has only 3 parameters then correct the oncomplete call)
Unrelated: I guess that you are using this function to close a specific dialog. Another way doing it would be assigning widgetVar attribute to your dialog:
<p:dialog id="testDialog" header="Create" widgetVar="createWidget">
<h:form id="CreateForm" prependId="false">
...
</h:form>
</p:dialog>
The widgetVar object will represent your dialog in the callback function so you can close it by call the hide() function of dialog:
function closeDialogIfSucess(xhr, status, args, createWidget) {
if(args.validationFailed || !args.loggedIn) {
jQuery('#testDialog').effect("shake", { times:3 }, 100);
} else {
createWidget.hide();
}
}
I want to reset JSF inputs to their original managed bean values after validation failed.
I have two forms inside the same page - the first form has a commandLink to initialize the second form. The second form is rendered as a dialog whose visibility is toggled through jQuery - for the purpose of this exercise, though, I can illustrate just with two forms on the same page. Also, while I'm using PrimeFaces 2.2.x in my app, the same behaviors appear with regular h:commandLink as well.
The issue I'm having is:
click link in first form to initialize second form
submit invalid values in second form
click link in first form again to initialize second form - invalid values still there and/or UIInput state is still invalid.
For example - take the following form
<h:form id="pageForm">
<h:commandLink actionListener="#{testBean.initialize}">Initialize, no execute
<f:ajax render=":dialogForm"/>
</h:commandLink>
<br/>
<h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=#this
<f:ajax execute="#this" render=":dialogForm"/>
</h:commandLink>
</h:form>
<h:form id="dialogForm">
<h:messages/>
String property - Valid: <h:outputText value="#{property.valid}"/>
<br/>
<h:inputText id="property" binding="#{property}" value="#{testBean.property}">
<f:validateLength minimum="3"/>
</h:inputText>
<br />
Int property - Valid: <h:outputText value="#{intValue.valid}"/>
<h:inputText id="intValue" binding="#{intValue}" value="#{testBean.intValue}">
<f:validateLongRange maximum="50" />
</h:inputText>
<br/>
<h:commandLink actionListener="#{testBean.submit}">
Submit
<f:ajax render="#form" execute="#form"/>
</h:commandLink>
<h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=#this
<f:ajax execute="#this" render="#form"/>
</h:commandLink>
</h:form>
Bean class:
#ManagedBean
#ViewScoped
public class TestBean {
private String property = "init";
private Integer intValue = 33;
// plus getters/setters
public void submit() { ... }
public void initialize() {
intValue = 33;
property = "init";
}
}
Behavior #1
click either "Initialize" link on the pageForm
inputs get initialized to "init", "33"
now submit something invalid for both fields like "aa", "99"
now click any of the "initialize" links again (they all seem to behave the same - makes no difference whether it's in the same form or different, or whether I have specified execute="#this" or not.)
Result => UIInput.isValid() = false, both values reset though ("init", "33").
Expected => valid = true (or is this not reasonable to expect?)
Behavior #2
click either "Initialize" link on the pageForm
inputs get initialized to "init", "33"
now submit something invalid for the text field but valid for the int field ("aa", "44")
now click any of the "initialize" links again
Result => "init", valid=false; 44, valid=true
Expected => "init", valid=true; 33, valid=true
I have also looked at:
JSF 2 - Bean Validation: validation failed -> empty values are replaced with last valid values from managed bean
and
How can I populate a text field using PrimeFaces AJAX after validation errors occur?
The suggestion to explicitly reset the state of UIInputs with resetValue does work, but I'm not happy with it.
Now, I sort of understand why the isValid is not resetting - my understanding of the JSF lifecycle is that once a value is submitted to a component, isValid is not reset until the component is successfully submitted and validated and the Update Model Values phase sets the bean value. So there may be no way around explicitly resetting the valid state in this case, since I want to use #{foo.valid} for conditional CSS styling.
What I don't understand, though, is why the components that successfully validated are not re-initializing from the bean. Perhaps my understanding of the JSF lifecycle is slightly off?
I understand the rules layed out in the answer to How can I populate a text field using PrimeFaces AJAX after validation errors occur? as they pertain to an individual component but not to the form as a whole - i.e., what happens if a component succeeds validation but the validation overall fails?
In fact, there may turn out to be no better way than explicitly calling resetValue on components. In my case, all of the dialogs are in the same big JSF view tree with the underlying page that opens them. So from JSF's perspective, the same view component state including invalid input values should be preserved until we navigate away from the view, as it has no visibility into how we're toggling display attributes client-side.
The only other thing that might work is if the components that make up the dialog are actually not rendered in the JSF view tree unless they're visible. In my case, they're always rendered, using CSS to toggle visibility.
I am trying to make a filter using selectOneMenu.
I have two categories, when one is selectect, must filter the results shown, and also the second category.
JSF code:
<div id="box-categories" class="box-left">
<b>Filter by topic</b>
<h:selectOneMenu id="cat1" binding="#{interfaceContainer.documentFormContainer.selectOnes['cat1'].selectOne}" rendered="true" onchange="javascript:refreshResults(); return false;">
<f:selectItems value="#{interfaceContainer.documentFormContainer.selectOnes['cat1'].items}" />
</h:selectOneMenu>
<b>and subtopic</b>
<h:selectOneMenu id="cat2" binding="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].selectOne}" rendered="true" onchange="javascript:refreshResults(); return false;" value="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].value}">
<f:selectItems value="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].items}" />
</h:selectOneMenu>
</div>
But I have problems when I try to get the values using this java code:
public String getStringValue(){
if ( this.selectOne ==null || this.getSelectOne().getValue()==null)
return "";
return this.getSelectOne().getValue().toString();
}
I realised that the problem is just with getValue(), because debugging, this.getSelectOne() is in the rigth value, but this.getSelectOne().getValue() is null.
Any idea??
Thanks in advance
UIInput#getValue() will return null when you attempt to access it during any phase before the Update Model Values phase. You're apparently accessing it at the "wrong" moment in the JSF lifecycle. Anyway, creating dependent dropdown menus in JSF without help of a shot of Ajax is terrible.
Long story short, here's how to do it: Populate child menu's (with complete and working code examples).