jsf ajax on IE click button twice reload the page - ajax

I want to use ajax in my app but on IE (Internet Explorer) there is a behavior that kept me from continuing.
When we have a simple form with a text field and a submit button with ajax. The button works the first time but subsequent call sends no ajax and the page is reloaded. the third time ok, then no ajax and so on. It's easy to test. I dont want a page reload on IE. In other Browser works fine and ther is no page reload. so my app can't run on IE because of this BUG?
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
>
<h:head>
<title>Employees App</title>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
</h:head>
<h:body>
<h:form id="myform" style="margin-top: 50px;margin-left: 50px">
<h:inputText value="#{testController.firstName}" id="firstName">
<f:validateLength minimum="3" maximum="50"/>
<f:validateRequired/>
</h:inputText>
<h:message for="firstName" errorClass="form-control-feedback" />
<h:commandButton value="Form1 Submit f:Ajax" type="submit">
<f:ajax execute="#form" render=":myform"/>
</h:commandButton>
</h:form>
</h:body>
</html>

f:ajax generates an onclick in the submit button. by clicking the first time the form is submitted and the form is rerendered after Ajax is finish. the onclick is in new generated html but in IE there is no Eventlistener registred for click you can see this analysing the button properties in IE DevTools. so the solution is to add manually the Eventlistener after an ajax call for new rendered elments. ist not easy but this works. i add manually every click function for new rendered elements. It works. now i have no trouble with reloading page.
<div id="test"></div>
<script>
document.getElementById("test").addEventListener("click", function( event ) {
// display the current click count inside the clicked div
event.target.textContent = "click count: " + event.detail;
}, false);
</script>

Related

PrimeFaces Gmap not rendering in ui : include tag

I have a problem with showing a Primeface p:gmap inside a ui:include component put in a layout page. I'm using the last version of primeface, mojarra and Tomcat 8.
this is my layout component where i try to render my google map:
<p:layoutUnit id="main_content" position="center" >
<ui:include src="#{pageManagingBean.page}.xhtml" />
</p:layoutUnit>
in the same page i have a button, when i click this:
<p:menuitem value="Display referencies Map" actionListener="#{pageManagingBean.setPage('gmapdata')}" icon="ui-icon-disk" update=":main_content" ajax="true"/>
the value of pageManagingBean.page change in the page with the p:gmap, and without reload the entire page, ui:include should load the gmap in the center layout, this is the gmapdata.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:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Google Map Displayed</title>
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript" ></script>
</h:head>
<h:body>
<h1>Google Map</h1>
<f:view contentType="text/html">
<p:gmap center="41.381542, 2.122893" zoom="15" type="HYBRID" style="width:100%;height:100%" widgetVar="gmap" />
</f:view>
</h:body>
</html>
When I click the menu item, the center layout show nothing, but if I change the p:menuitem ajax="true" in ajax="false" all work fine and gmap is showed in the correct position, so why gmap don't render in ajax but work fine without?
EDIT
This problem is not only the rendering of the page gmap but also of the other pages that I try to load ajax in that part of the layout , for example, I have a page with a table of the work that should appear with the same mechanism , but show only if I impose ajax = false and the subsequent update of the entire page.
UPDATE
I did several tests and thus constituting the page with gmap ,
<h:head>
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
</h:head>
<h:body>
<f:view contentType="text/html">
<h1>Google Map</h1>
<p:gmap center="41.381542, 2.122893" zoom="15" type="HYBIRD"
style="width:600px;height:400px" />
</f:view>
</h:body>
</html>
and including ui:include into a <h:form id="main_content"> tag, who will update thanks to the p:menuItem...update="main_content"
content in the tag is added to the page with the ui : include , but is not rendered map , however if I enter manually , along with ui : include , the tag <gmap> in my mainpage: at first opening the map is rendered (map in the tag gmap than i have hadded manually), but when the layout is updated in ajax through the usual function by <p:menuItem> , both maps ( gmap added manually and that loaded by ui : include ) disappear.
obviously everything works setting ajax = false .
I can not explain the problem
I'm not sure but it could be related to the place of the google maps script
I am not in the same situation, I have a template using ui:inser ui:composition, ui:define, ui:include...
My template:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<ui:insert name="resources">
<ui:include src="/template/resources.xhtml"/>
</ui:insert>
<title>MyApp</title>
<ui:insert name="scripts"/>
<link rel="icon" type="image/png" href="resources/img/favicon.png"/>
</h:head>
<h:body>
<f:view contentType="text/html">
<ui:insert name="header">
<ui:include src="/template/header.xhtml"/>
</ui:insert>
<ui:insert name="menu">
<ui:include src="/template/menu.xhtml"/>
</ui:insert>
<ui:insert name="content"/>
<ui:insert name="footer">
<ui:include src="/template/footer.xhtml"/>
</ui:insert>
</f:view>
</h:body>
</html>
and when I build the page with g:map I do
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
template="/template/template.xhtml"
xmlns:p="http://primefaces.org/ui">
<ui:define name="scripts">
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"/>
</ui:define>
<ui:define name="content">
<p:gmap center="41.381542, 2.122893" zoom="15" type="HYBRID" style="width:100%;height:100%" widgetVar="gmap"/>
</ui:define>
</ui:composition>
because the scripts has to be loaded in the head
And when you update main_content using ajax, what going on in the head?
I think you have to put the script in the head, form the beginig, so that the page is load with the script anyway.
EDIT
And you could have problem if you are using forward based navigation because primefaces don't support that
http://primefaces.org/faq.html
you have to concat view id with "?faces-redirect=true" in action attribute of commandLink or commandButton
UPDATE
Generally there is a Javascript function to initialize the map
This function (Generally called initialize()) is call on the load event of the page
https://developers.google.com/maps/documentation/javascript/events
when you do an ajax request you should call this function to initialize the map
I try to execute your code but I have a jquery error: "TypeError: b is undefined" jquery.js.xhtml:1:30
It's seems that it is a javascript problem, I don't know how to solve it
Update form tag: <h:form prependId="false" id="main_content">. In my case it is worked when i kept prependId="false".

First click on commandButton doesn't redirect to another page

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.

Form submit vs ajax execute="#form"

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

Automatically set focus on p:editor on page load

How do I automatically set the focus on <p:editor> on page load?
After page is loaded I would like to be able to write in the editor without an additional click on the editor panel.
Primefaces provide attribute 'widgetVar', so you can get element from client and focus it:
<h:head>
<script type="text/javascript">
function test() {
xxx.focus();
}
</script>
</h:head>
<h:body onload="test()">
<h:form id="form">
<p:inputText id="rongnk" value="test"/>
<p:editor widgetVar="xxx" id="nkrong" value="123" width="600"/>
</h:form>
</h:body>

Trouble to display deployJava button on ajax rerender

I'm having trouble displaying the deploy-java button on ajax rerender
<h:form id="deployJavaForm" rendered="#{myBean.shouldRender}">
<h:outputScript library="js" name="http://java.com/js/deployJava.js" target="head" />
<script type="text/javascript">
deployJava.createWebStartLaunchButton('blah.jnlp', '1.7.0');
</script>
</h:form>
when
myBean.shouldRender == true
and the form is updated the only thing being displayed (on a white page) is the deployJava-button and the request is left hanging. if shouldRender is true on the initial request, page and button is displayed correctly.
Im using primefaces in case it can help.
What I want to do is to have the button to be displayed correctly regardless if its part of a ajax rerender or a complete initial request.
Update:
I did my homework and created a minimal example that still reproduces the problem. It seems I still get the same problems regardless if script declaration is in head or in body (I have copy of deployJava.js in resources/js)
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<!-- <script type="text/javascript" src="http://java.com/js/deployJava.js" />-->
</h:head>
<h:body>
<h:outputScript library="js" name="deployJava.js" target="head" />
<h:form id="djForm">
<script type="text/javascript">
deployJava.createWebStartLaunchButton(
'test.jnlp', '1.7.0');
</script>
<p:commandButton value="update" update="djForm" />
</h:form>
</h:body>
</html>
edit: (specialgems)
below test give same problem as observed earlier.
<h:outputScript>
deployJava.createWebStartLaunchButton(
'test.jnlp', '1.7.0');
</h:outputScript>
edit: added picture
after click of update button, only deployJava button is rendered and page is loading
edit (daniel): both on success and oncomplete give same behaviour :(
<h:form id="djForm">
<h:outputScript>
function abcefg() {
deployJava.createWebStartLaunchButton('test.jnlp', '1.7.0');
}
</h:outputScript>
<p:commandButton value="update" update="djForm" onsuccess="abcefg()" />
</h:form>
Alternatively to using js and css visibility described in my comment you can write own composite button component. Using Firebug you can investigate which markup is generated by the deployJava.createWebStartLaunchButton script and add it by yourself statically. So your component could be:
<!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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<head>
<title>deployJava Button component</title>
</head>
<body>
<composite:interface>
<composite:attribute name="version" required="true"
type="java.lang.String" />
<composite:attribute name="url" required="true"
type="java.lang.String" />
</composite:interface>
<composite:implementation>
<a onmouseover="window.status=''; return true;"
href="javascript:if (!deployJava.isWebStartInstalled("#{cc.attrs.version}")) {if (deployJava.installLatestJRE()) {if (deployJava.launch("#{cc.attrs.url}")) {}}} else {if (deployJava.launch("#{cc.attrs.url}")) {}}"><img
border="0" src="//java.com/js/webstart.png" /></a>
</composite:implementation>
</body>
</html>
so your page will be:
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:comps="http://java.sun.com/jsf/composite/comps"
xmlns:p="http://primefaces.org/ui">
<h:head>
<!-- <script type="text/javascript" src="http://java.com/js/deployJava.js" />-->
</h:head>
<h:body>
<h:outputScript library="js" name="deployJava.js" target="head" />
<h:form id="djForm">
<comps:deployJavaButton version="1.7.0" url="test.jnlp" rendered="#{myBean.shouldRender}" />
<p:commandButton value="update" update="djForm" />
</h:form>
</h:body>
</html>
The main idea is to avoid executing button creation script twice and more.
May be using h:panelGroup instead of h:form will help. Something like that:
<h:form id="djForm">
<h:panelGroup rendered="#{myBean.shouldRender}">
<script type="text/javascript">
deployJava.createWebStartLaunchButton(
'test.jnlp', '1.7.0');
</script>
</h:panelGroup>
<p:commandButton value="update" update="djForm" />
</h:form>

Resources