I have a facelet that shall dynamically list teachers loaded from database with name, profile picture etc. etc. Every listed teacher has its own contact formular, which gets hidden after pageload, and a button "get in touch" which, onclick, shall open the contact formular below and hide the button "get in touch". The formular has some text fields and a submit button "send request". After clicking "send request" I want to call a backing bean method which saves the request in the database, and, with javascript, hides again the contact formular and shows the "get in touch" button instead.
Here is the page listing the teachers:
<ui:composition template="/WEB-INF/templates/layout.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<ui:define name="content">
<script type="text/javascript">
$(document).ready(function () {
$(".request_form").hide();
});
</script>
<ui:repeat id="teachers" var="teacher" value="#{teachersController.teachers}" varStatus="it">
profile picture, infos, etc.
<p:button id="btn_open_request_form"
value="get in touch"
onclick="$('#teachers:#{it.index}:request_form').show(300); $(this).hide(); return false;"/>
<h:form class="request_form" id="request_form" prependId="false">
Text inputs for email, message...
<p:button value="#{msg['cancel']}"
onclick="$('#teachers:#{it.index}:request_form').hide(300); $('#teachers:#{it.index}:btn_open_request_form').show(); return false;"/>
<p:commandButton value="send request"
process="@form"
update="@form"
action="#{teachersController.sendRequest(teacher.id)}"
oncomplete="$('#teachers:#{it.index}:request_form').hide(300); $('#btn_open_request_form_#{it.index}').show();"
/>
</h:form>
<h:messages></h:messages>
<br/>
</ui:repeat>
</ui:define>
</ui:composition>
In a first attempt I was using c:forEach instead of ui:repeat to iterate over the teachers. The showing/hiding of the contact formular and buttons with jQuery was working perfectly, but the action method of p:commandButton could not be called and no request was sent, so I switched to ui:repeat.
Now, the requests are saved to the database, but the hiding/showing with Javascript doesn't work anymore. The formulars get hidden by pageload as expected. But then, when clicking on "get in touch", the button itself gets hidden, as I want, but no formular is shown.
It took me a while to figure out how jsf generates all the id's but I got it right in the end by checking the generated html. Here is the generated html of the button:
<button id="teachers:1:btn_open_request_form"
name="teachers:1:btn_open_request_form"
type="button"
class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"
onclick="$('#teachers:1:request_form').show(300); $(this).hide(); return false;;window.open('/lehrerverzeichnis/faces/requests/teachers.xhtml','_self')">
here the one of the form:
<form id="teachers:1:request_form"
name="teachers:1:request_form"
method="post"
class="request_form" ...>
What am I getting wrong? Before, when using c:forEach, it worked well (with different id's of course). But the selector in jQuery function matches the form id, why isn't it shown after clicking the button? The button itself gets hidden by the command afterwards, so the onclick function gets called for sure.
It seems to me that combining Javascript and JSF is not a good idea. What else could I do instead?
Thank you very much in advance..
SOLVED It was just a stupid mistake. The semicolon in the jQuery Selector needs to be escaped. In the created html source, $('#some:id') would need to be $('#some\:id'). To have two backslashes remaining they must be escaped as well in the facelet. So in the .xhtml file there must be written $('#some\\\:id'), so 4 backslashes before the colon are necessary that 2 survive in the created html.
Thats why I prefer Java, it would at least have told me where the problem is.. :D