I'm using JSF2.1.
What is the difference beetween execute="#form" and this.submit() in the code below?
<f:ajax execute="#form" render="#form"/>
and:
<h:form onkeypress="if (event.keyCode == 13) this.submit();">
The former seems to submit the values and re-render the form, while the latter causes a page refresh. Is there any way to use ajax when the enter key is pressed in the form? I'm trying to detect the enter key being pressed in an inputText box. I've tried things like this:
<h:inputText value="#{a.name}" >
<f:ajax execute="#this" />
</h:inputText>
but this just causes the values to be submitted when you click on something else (after valueChange).
In order to answer your question's title, the difference between them is that a form submit sends the whole form and reloads the view, while an ajax form execution also submits the whole form, but using an ajax request which can be used to render only a specific part of the view before response happens.
Regarding to your question content, the form submit by pressing the Enter key is implemented in the major browsers for single input forms. There's no need of javascripting the onkeypress event, as the browser will detect that and send the form by default.
So the next code piece has the same result for server side, either pressing the Send button or the Enter key: The value attribute being set. Note that in the second form, where the <h:inputText /> has an ajax behaviour, the h:outputText value is also refreshed (even not being specified a render attribute) when hitting the Enter key, that's because of the full submit request being prioritized over the ajax request and the whole page being reloaded. Only Google Chrome seems to tell about that conflict: httpError:The Http Transport returned a 0 status code. This is usually the result of mixing ajax and full requests.
Full request:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}" />
<h:commandButton value="Send" />
</h:form>
</body>
</html>
Ajax request:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}">
<f:ajax />
</h:inputText>
<h:outputText value="Echo: #{bean.value}" />
</h:form>
</body>
</html>
When the form has more than an input field you can use such a javascript verification for sending the form if there's no any submit button, using full submit request. If there's, doing that is unecessary.
Finally, if you want to perform an ajax request when hitting the key and update model values, use onkeypress attribute:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}"
onkeypress="if (event.keyCode == 13) {onchange(); return false; }">
<f:ajax render="echo" />
</h:inputText>
<h:inputText value="#{bean.value2}" />
<h:outputText id="echo" value="Echo: #{bean.value}" />
</h:form>
</body>
</html>
Remind that it's advisable to use a submit button for plain accessibility matters.
See also:
JSF 2.0: ajax request when press ENTER
Jsf calling bean method from input text when pressing enter
Related
When I enter valid value (only digits) to inputText and click commandButton then I'am redirected to response.xhtml.
When I enter invalid value, click on page background, then change event is triggered, message is displayed.
Now when I enter valid value and click commandButton, message hides, but I am not redirected.
When I click second time I am redirected.
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid>
<h:inputText id="value" value="#{bean.value}">
<f:validateRegex pattern="\d+"/>
<f:ajax event="change" execute="#this" render="#this valueMessage"/>
</h:inputText>
<h:message id="valueMessage" for="value"/>
</h:panelGrid>
<h:commandButton value="OK" action="response"/>
</h:form>
</h:body>
</html>
response.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Value is <h:outputText value="#{bean.value}"/>
</h:body>
</html>
Bean.java
package app;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class Bean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Your concrete problem is caused by the hiding message, which in turn causes the command button to move up before its own click event finishes, and thus not sitting below the mouse pointer anymore when the mouse button is released and about to trigger the form submit. If you move the message component to below the command button component like so,
<h:commandButton value="OK" action="response"/>
<h:message id="valueMessage" for="value"/>
... then the command button will stay at the same place in the UI when the message hides, and thus its click event will be successfully received and trigger the form submit.
This is just an UI design problem, not a technical problem. You need to try to make sure that the button doesn't move away before its click event finishes.
One way is to make the form 2-column wide so that the message is shown next to the input field instead of below it, hereby not occupying more horizontal space:
<h:panelGrid columns="2">
An alternative is to delay the ajax request with <f:ajax delay> attribute (only available since JSF 2.2). I tested with a few values and 100~200ms seems acceptable to cover the time span of an average click (the time from the mouse button press until the mouse button is actually released). This way the ajax request is actually not fired when the submit button is clicked, hereby avoiding the shift of the button (and "unnecessary" validation).
<f:ajax render="#this valueMessage" delay="150" />
(note that event="change" and execute="#this" are the default values already, they are already for clarity omitted in above example; technically render="#this" is also strange, but I just kept it in, for the case you actually want to redisplay a changed value after some conversion step)
You may have to do it like this in your index.xhtml
<h:form>
<h:panelGrid>
<h:inputText id="value" value="#{bean.value}">
<f:validateRegex pattern="\d+" />
</h:inputText>
<h:message id="valueMessage" for="value"/>
</h:panelGrid>
<h:commandButton value="OK" action="response" >
<f:ajax execute="value" render="value valueMessage"/>
</h:commandButton>
</h:form>
and btw in your code the first click is for change event not for the button so if you try to click anywhere in the page except the button it will make the validation to disappear and the button will redirect you from first hit.
I use JSF in implementation MyFaces 2.0
I have 2 jsf pages login.xhtml and register.xhtml.
login.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>System CollDoc</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="3" >
<h:outputLabel for="username" value="Login:"/>
<h:inputText id="username" value="#{userManager.userName}" required="true" requiredMessage="#{msg.requiredLoginMsg}">
<f:ajax event="blur" render="usernameMessage"/>
</h:inputText>
<h:message id="usernameMessage" for="username" />
<h:outputLabel for="password" value="#{msg.password}"/>
<h:inputSecret id="password" value="#{userManager.password}" required="true" requiredMessage="#{msg.requiredPassMsg}">
<f:ajax event="blur" render="passwordMessage" />
</h:inputSecret>
<h:message id="passwordMessage" for="password" />
<h:commandButton value="#{msg.login}" action="#{userManager.login}"/>
</h:panelGrid>
</h:form>
<h:messages id="messages" globalOnly="true"/>
<h:link value="#{msg.register}" outcome="register.xhtml"/>
</h:body>
</html>
register.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>System CollDoc</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="3" >
<h:outputLabel for="login" value="Login:"/>
<h:inputText id="login" value="#{registerBacking.registerLog}" required="true" requiredMessage="#{msg.requiredLoginMsg}">
<f:ajax event="blur" render="usernameMessage"/>
</h:inputText>
<h:message id="usernameMessage" for="login"/>
<h:outputLabel for="pass" value="#{msg.password}"/>
<h:inputSecret id="pass" value="#{registerBacking.registerPass}" required="true" requiredMessage="#{msg.requiredPassMsg}">
<f:ajax event="blur" render="passwordMessage" />
</h:inputSecret>
<h:message id="passwordMessage" for="pass" />
<h:commandButton value="#{msg.login}" action="#{registerBacking.register}"/>
</h:panelGrid>
</h:form>
<h:link class="link" value="#{msg.returnTxt}" outcome="/pages/login.xhtml"/>
</h:body>
</html>
I run my application and first i see login.xhtml page. I click at first inputText "username" and next at inputSecret "password" (validation for "username" is run by ajax request on blur), next at link to register page (validation for "password" is run by ajax request on blur) and i get dialog with error:
Error Message: Request failed with status 0 and reason
--------------------------------------------------------
Calling function:myfaces._impl.xhrCore._AjaxRequest
Error Name: httpError
--------------------------------------------------------
Note, this message is only sent, because project stage is development and no other error listeners are registered.
I click "ok" button and i get register.xhtml page in my web browser. At register page situation is same: I click at inputText "login", next at inputSecret "pass" (validation for "login" is run by ajax request on blur) next i click link back to login page or button to run business logic (validation for "pass" is run by ajax request on blur) and i get same error
What does error mean? What is wrong?
Edit:
I run my application again now and i don't get any error message. Why do I get this error only sometimes?
It is a result of mixing AJAX and 'regular' requests. When the button is hit two requests run in parallel: one - AJAX request for validation on blur, and second - form submit of commandButton.
JSF detects it when AJAX request is completed and reports it as a potential problem (e.g. if both requests did some actions on server side which were inter-dependent).
Probably simplest way to fix it in your case is to make the button do AJAX request as well (add f:ajax to the h:commandButton), then JSF will put the request to the queue what will guarantee that requests are made serially but not concurrently.
I have a jsf code like this. When user finish to input name and comment and press 'Enter', the content can show in 'Content........' this part.
<h:form id="all_comments">
Content........
</h:form>
<h:form id="submit_comment">
<h:inputText id="name_box" value="#{ManagedBean.user}"/>
<h:inputText id="content_box" value="#{ManagedBean.comment}" />
</h:form>
I want to use ajax finish it, and I try like this:
<h:form id="all_comments">
Content........
</h:form>
<h:form id="submit_comment">
<h:inputText id="name_box" value="#{ManagedBean.user}"/>
<h:inputText id="content_box" value="#{ManagedBean.content}">
<f:ajax event="keydown"
listener="#{ManagedBean.addComment}"
execute="comment_name_box comment_content_box"
rendered=":all_comments" />
</h:inputText>
</h:form>
But I failed, can I achieve that when user press 'Enter', data will be processed by ManagedBean, then using ajax update the page.
You've got some points missing:
You need to send an AJAX call only when enter key was pressed, so you need to bind <h:inputText> tag's onkeydown attribute with JavaScript code for that;
<f:ajax> attribute is render, not rendered;
submit_comment form should be rerendered as well, so that new data will be presented to the user, and the placeholders have to be refreshed in AJAX listener as well.
Here is the solution when you want to submit the second form on that event:
<h:form id="all_comments">
Content........
</h:form>
<h:form id="submit_comment">
<h:inputText id="name_box" value="#{managedBean.user}"/>
<h:inputText id="content_box" value="#{managedBean.content}"
onkeydown="return (event.keyCode == 13);">
<f:ajax event="keydown"
listener="#{managedBean.addComment}"
execute="#form"
render="#form :all_comments" />
</h:inputText>
</h:form>
with
public void addComment(AjaxBehaviorEvent abe) {
comments.add(new Comment(user, content));
user = "";
content = "";
}
The code below is the tabView, followed by the structure of the loaded page. For the commandButton, I have tried actionListener, different combinations of render and update referencing the target inputtextarea (req) explicitly, etc. The action works fine when the form runs in its own page (not within a tab).
In the "preRenderView" event, I initialize data structures, which are populated when the form displays. Problem is when I click on the Preview button. Normally the action fires, the handling method assembles the data for display in the preview inputextarea (req), and it's displayed.
Strangely, when I click the button, the action is NOT called, although there is activity calling my other tabs' loadReqEvents, and in the outer page hosting the tabView. I suspect this is a request-response nuance of JSF that I'm unaware of. Thanks for help.
<p:tabView id="tbv" dynamic= "true" activeIndex="#{sessionController.activeTab}" styleClass="tabview-style">
<p:tab id="rtmTab" styleClass="tab-style" title="RTM" closable="false" titletip="Requirements Traceability Matrix">
<ui:include src="url(./../rtm.xhtml"/>
</p:tab>
<p:tab id="composeTab" styleClass="tab-style" title="#{sessionController.composeTabTitle}" rendered="#{sessionController.crudTabRendered}" closable="false" titletip="Composition Form">
<ui:include src="url(./..#{sessionController.composeUrl}.xhtml"/>
</p:tab>
<p:tab id="objTab" styleClass="tab-style" title="Object / Data Model" closable="false" titletip="Object and Data Model View">
<ui:include src="url(./../objView.xhtml"/>
</p:tab>
</p:tabView>
</p:layoutUnit>
<p:layoutUnit id="formLayout" position="center" gutter="0" styleClass="form-layout">
<h:form>
<f:event listener="#{attrDefController.loadReqEvent}" type="preRenderView"></f:event>
<p:panel style="background-color:rgb(222,231,254);width:925px;height:98%;margin-top:-4px;margin-left:-8px">
<h:panelGrid columns="7" style="margin-right:-8px" cellpadding="2">
<h:commandButton id="preview" value="Preview" action="#{attrDefController.previewReqAction}" style="width:100px; margin-top:2px">
<f:ajax execute="#form" render="req"/>
</h:commandButton>
</h:panelGrid>
</p:panel>
</h:form>
</p:layoutUnit>
Without seeing the markup for where the component req is declared, I assume that it exists in one of the xhtml files specified in the ui:include.
The problem is that the render attribute of the f:ajax is specifying an id which does not exist on the page. The reason for this is that is that the components client ID will be prefixed with the client id of its parent UINamingContainer.
Not all JSF components are a UINamingContainer, form definitely is which is why you will typically see the ID of the form prefixed to the client id of a component. Eg:
<h:form id="formone">
<h:outputText id="textComponent" value="YO" />
<h:commandButton ...>
<f:ajax update="textComponent" />
</h:commandButton>
</h:form>
<h:form id="formtwo">
<h:commandButton ...>
<f:ajax update=":formone:textComponent" />
</h:commandButton>
</h:form>
In the above example the client ID of textComponent is actually formone:textComponent. Now the command button in the example above can still reference it by its Actual ID because it happens to be in the same UINamingContainer as its sibling component.
The commandButton in the other form however must access it by its full client id because it is not a sibling of textComponent. It does this by prefixing the client ID with the universal selector : and then following that with the entire client ID of the textComponent.
Now what does this have to do with your problem?
The PrimeFaces TabView component happens to be a UINamingContainer as well.
So that means that to Ajax render the component with ID req you will need to specify an ID for your form and call it in this way...
render=":formid:tbv:req"
I hope this makes sense.
Requirement is to render a component outside the form after an ajax call. I have tried with the following code but the text was not being rendered.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ads="http://java.sun.com/jsf/composite/components">
<ui:include src="secondfile"/>
<h:panelGroup id="panel1" rendered="#{bean.access}">
Some text
</h:panelGroup>
</ui:composition>
Secondfile:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ads="http://java.sun.com/jsf/composite/components">
<f:ajax render="#form _panel1">
<h:selectOneRadio id="access" value="#{beanTO.access}">
<f:selectItem itemValue="true" itemLabel="yes"/>
<f:selectItem itemValue="true" itemLabel="yes"/>
</h:selectOneRadio>
</f:ajax>
</ui:composition>
I assume that you've changed the default naming container separator character from : to _, otherwise you should have used :panel1 instead of _panel1)
You're trying to ajax-render a component which is by itself conditionally rendered by the server side. This will not work when the component is not rendered in first place. JS won't be able to locate the desired HTML element to update after the ajax response arrives. You need to wrap it in another component which is always rendered to the HTML output and set the rendered condition on the wrapped component.
<h:panelGroup id="panel1">
<h:panelGroup rendered="#{bean.access}">
Some text
</h:panelGroup>
</h:panelGroup>
See also:
Communication in JSF2 - Ajax rendering of content which is by itself conditionally rendered