Use jQuery (or JSF way) to prevent h:commandButton submit - javascript

I have a JSF page(already register jQuery in header) contains indicator, reason and a h:commandButton used for submit h:form. The indicator has two values Y and N.
The logic I try to build is when page load and indicator = Y(in jQuery below is indicator.data("prev") == 'Y'), if user toggle from Y to N but NOT type in any word in reason, even the user click the h:commandButton, the form should NOT submitted.
In short, before submit, it should check status of indicator's current and previous value relation is turn from Y to N(I set this logic part in jQuery script section), also need to check reason is not empty. I guess to implement such checking operations may need to re-organize code structure.
Below is my current code which missing this logic, never prohibit a submit and cause conflict on backing bean, . As I am new to jQuery and JSF, could someone tell me how to prevent this submit ? Thank you.
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<h:head>
<title>myPage</title>
<h:outputScript name="jquery.js" target="head"/>
</h:head>
<f:event type="preRenderView" listener="#{myPage.getmyPage}" />
<h:body>
<f:view>
<h:form name ="myPage" id ="myPage">
<table>
<tr>
<td align="left">
<h:selectOneMenu id="indicator" value="#{myPage.indicator}">
<f:selectItem itemValue="Y" itemLabel="YES" />
<f:selectItem itemValue="N" itemLabel="NO" />
</h:selectOneMenu>
</td>
<td>
<h:inputTextarea id="reason" value="#{myPage.reason}">
</h:inputTextarea>
</td>
<td>
<h:commandButton id="submit" value="Submit"
onclick="if (! confirm('Do you want to update?')) return false" action="#{myPage.update}">
</h:commandButton>
</td>
</tr>
</table>
</h:form>
</f:view>
// TODO: I want to add the logic to prevent h:commandButton submit(e.g disable the button) when reason is empty
// and indicator value turn from 'Y' to 'N', the jQuery section reflect the case when toggle from 'Y' to 'N',
// reason editable, as it need to consider two elements(indicator value/ reason value) at the same time,
// how should the code look like ?
<script type="text/javascript">
$(window).load(function() {
var indicator = $(document.getElementById("myPage:indicator"));
// set the indicator pre data
indicator.data("prev", indicator.val());
// Handle initial status of indicator, when page load, if it is 'Y' open reason field
// if it is 'N' disable reason field,
if(indicator.data("prev") == 'Y') {
$(document.getElementById("myPage:reason")).prop('disabled', false);
} else {
$(document.getElementById("myPage:reason")).prop('disabled', true);
}
// Handle change status of indicator,
indicator.change(function(data){
var jqThis = $(this);
var after_change = jqThis.val();
var before_change = jqThis.data("prev");
if(before_change == 'Y' && after_change == 'N'){
$(document.getElementById("myPage:reason")).prop('disabled', false);
}
});
});
</script>});
</h:body>

Basically you could implement some logic to disable your commandbutton depend on some conditions. For instance :
<h:commandButton id="submit" value="Submit" disabled=#{myPage.isSubmitButtonDisabled()}
onclick="if (! confirm('Do you want to update?')) return false" />
Then in backing bean you should implement logic which you want to achieve like :
public boolean isSubmitButtonDisabled() {
return indicator.equals("N") && reason.isEmpty();
}
Finally to process changes on indicator selection you should add onchange="submit()" to your <h:selectOneMenu> component. Logic for button enabling/disabling could be further expanded with reaction to typed text in reason text area with similiar manner, for instance by addig onkeyup="submit()". Of course this would require to use render attribute to prevent pafe refresh. This is of course some way of do that, but it could point you to solution which satisfy you

Related

Javascript function inside ui:repeat to show/hide contact formular not working

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

Redirect and reset from one html page to another one

I need to redirect from my destination.xhtml to my index.xhtml, making a reset to the inputText in this last one page.
The problem is, I need inputText not to be automatically reset when I normally refresh my index, just in the case it is redirected from my destination.xhtml
Thank you all.
I come from:
<h:body>
<f:view>
<h:form>
<h:outputLabel value="UserID: "/><h:outputText value="#{userMBean.user_login}"/>
<h:outputLabel value="Activation code: "/><h:outputText id="act_code" value="#{userMBean.act_code}" style="color:red"/><br></br>
<h:message for="act_code"/>
<h:commandButton action="index" value="Back"/>
</h:form>
</f:view>
</h:body>
And in my index I have:
<h:form>
<h:inputText required="true" value="#{userMBean.user_login}">
<f:validator validatorId="tencko.model.EmailValidator"/>
</h:inputText>
<h:commandButton action="#{logicBean.lookingfor()}" value="Search"/>
</h:form>
Base the replacing logic on the Referrer (the page where the user comes from). In javascript you get it like this
var ref = document.referrer
See MDN for more information
I fixed the problem just setting the Manage Bean user login to null, then when I return index from my Logic Bean, that value is just null, so it looks reset, but it's just that value, all the Manage Bean object keeps being the same as before, until you start another search.
Thank you all anyway.
MBean userVO = (MBean) ve.getValue(context);
// Reset login used
userVO.setUser_login(null);
return "index";

how javascript alert function work in String var Of java on web browser

i have a String var in class
String message;
private int checkConstraints()
int a = 0;
if (docProcessId==0) {
a++;
message = "<script language=\"javascript\"> alert('Please Select Doc Process Name'); </script>";
}else if (refTypeName.equals("")) {
a++;
message = "<script> alert('Enter Reference Type Name!');</script>";
}
return a;
}
actually i am doing like this but when this method is called not equals to 0 then message equals to whole the string print on page not giving alert any solution please
JSF by default HTML-escapes all model values as part of XSS attack prevention. Your concrete problem suggests that you had no idea of that. You can "solve" it by using <h:outputText> with escape attribute set to false.
<h:outputText value="#{bean.message}" escape="false" />
However, your concrete problem is bigger. You're in JSF/MVC perspective basically making two major design mistakes here:
Writing HTML code in model instead of in the view.
Performing validation in an action method instead of in a validator.
You should be writing HTML code in the view, not in the model. You should be performing validation using a normal JSF validator. JSF has a lot of builtin validators.
Besides, not really a design mistake, but more an user experience mistake, there's a third mistake: using JavaScript alerts to show validation messages. This is simply too 1990 and Web 1.0. We're currently in 2013 and have learnt a lot, a lot of the user experience failures made back then. Using JavaScript alerts to show validation messages is one of them.
Here's the right approach using JSF-provided validation facilities:
<h:form>
<h:selectOneMenu value="#{bean.docProcessId}" required="true"
requiredMessage="Please Select Doc Process Name">
<f:selectItems ... />
</h:selectOneMenu>
<h:inputText value="#{bean.refTypeName}" required="true"
requiredMessage="Enter Reference Type Name" />
<h:commandButton value="submit" />
<h:messages />
</h:form>
That's it. The required="true" tells JSF that those inputs are required. The requiredMessage attribute allows you to specify custom messages for required validation. The messages will be displayed in place as declared by <h:messages>. You can customize the layout by layout attribute and by CSS means like infoClass, errorClass, etc. You can even manually loop over it and manually create annoying alerts for each message instead of using <h:messages>:
<ui:repeat value="#{facesContext.messageList}" var="message">
<script>alert("#{message.summary}");</script>
</ui:repeat>

EL expression inside p:commandButton onclick does not update/re-render on ajax request?

The onclick attribute of my commandButton has some EL dependent Javascript inside. To be more specific, here is that piece of code:
<p:commandButton
onclick="javascript: if('#{userBean.user.friendList.size() gt 0}' == 'true') deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />
deleteFriendsConfirmDialog clears the list of friends and updates the #form. The list of friends, commandButton and the dialogs are all in that form.
So I click the button, confirmation dialog comes up (because the length of friends' list is gt 0), I confirm and the list is emptied, the view is updated. However, when I click the Delete all friends? button once more, the confirmation dialog comes up again. Since the length of the list is now 0, I instead expect the error dialog to show.
That, I guess, is because the Javascript written inside onclick is not updated (although the button is in the form).
Edit: Changing #{userBean.user.friendList.size() gt 0} to #{not empty userBean.user.friendList} doesn't work neither.
How come? What's wrong here?
Any help appreciated. :)
Indeed. PrimeFaces (and standard JSF) does not re-evaluate the EL in on* attributes on a per-request basis. It only happens on a per-view basis. RichFaces however does that in <a4j:xxx> components.
You need to solve the problem differently. I suggest to use the visible attribute of the <p:dialog> instead.
<h:form>
...
<p:commandButton value="Delete all friends?" update=":deleteDialogs" />
</h:form>
...
<h:panelGroup id="deleteDialogs">
<p:dialog id="deleteFriendsConfirmDialog" visible="#{facesContext.postback and not empty userBean.user.friendList}">
...
</p:dialog>
<p:dialog id="friendsAlreadyDeletedErrorDialog" visible="#{facesContext.postback and empty userBean.user.friendList}">
...
</p:dialog>
</h:panelGroup>
An alternative is to use PrimeFaces' RequestContext in the bean's action method which allows you to execute JavaScript code programmatically in bean's action method (although this tight-couples the controller a bit too much with the view, IMO).
<p:commandButton value="Delete all friends?" action="#{userBean.deleteAllFriends}" />
with
RequestContext context = RequestContext.getCurrentInstance();
if (!user.getFriendList().isEmpty()) {
context.execute("deleteFriendsConfirmDialog.show()");
} else {
context.execute("friendsAlreadyDeletedErrorDialog.show()");
}
Unrelated to the concrete problem, your original onclick, while it does not work out in your particular case, shows some poor practices. The javascript: pseudoprotocol is superfluous. It's the default already. Remove it. Also the test against == 'true' is superfluous. Remove it. Just let the EL print true or false directly. The following is the proper syntax (again, this does not solve your problem, just for your information)
<p:commandButton
onclick="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />
It would have worked if you were using RichFaces' <a4j:commandButton>.
<a4j:commandButton
oncomplete="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />

jsp in javascript

I've created a jsp page. In that when i select 1 check-box or both check-box or none, the corresponding text-boxes and list-box must be displayed in the same page.
For that i tried of calling a javascipt function when i click the checkbox. The javascript function contain code to display the textboxes. But it didn't work.
Since I'm doing this project in struts, I don't know how to get check-box value. And calling of JavaScript function works. But didn't enter into jsp code in JavaScript function.
My code is
<tr>
<td>SEJ:</td>
<td>SEJ 1:<html:checkbox property="sej1" value="on" onclick="checkbox_trial()"></html:checkbox></td>
<td>SEJ 2:<html:checkbox property="sej2" value="on" onclick="checkbox_trial()"></html:checkbox></td>
</tr>
<script type="text/javascript">
function checkbox_trial()
{
<% if(request.getParameter("sej1")=="on"){
%>
<tr><td>SEJ1 Age<html:text property="sej1_age"></html:text></td></tr>
<tr><td>SEJ1 DOI<html:text property="sej1_doi"></html:text></td></tr>
<%}
else if(request.getParameter("sej2")=="on"){%>
<tr><td>SEJ2 Age<html:text property="sej2_age"></html:text></td></tr>
<tr><td>SEJ2 DOI<html:text property="sej2_doi"></html:text></td></tr>
<%}
else if((request.getParameter("sej1")=="on")&&(request.getParameter("sej2")=="on")){%>
<tr><td>SEJ1 Age<html:text property="sej1_age"></html:text></td></tr>
<tr><td>SEJ1 DOI<html:text property="sej1_doi"></html:text></td></tr>
<tr><td>SEJ2 Age<html:text property="sej2_age"></html:text></td></tr>
<tr><td>SEJ2 DOI<html:text property="sej2_doi"></html:text></td></tr>
<%}
else{%>
NOTHING <% } %>
}
This is how it works: Java/JSP runs at webserver, produces HTML/CSS/JS, webserver sends it to webbrowser, webbrowser runs HTML/CSS/JS. Not Java/JSP. Rightclick the page in webbrowser and choose View Source. If Java/JSP has done its job right, you shouldn't see any line of it in there.
If you want to invoke Java/JSP code using JavaScript, you've got to invoke another HTTP request to the webserver so that it can execute the Java/JSP code based on the specific request. You can do that by either submitting the form or firing an asynchronous (ajaxical) request.
Given the skills shown as far and the fact that you're using Struts, I think ajax is going to be a bit too complex. I'd suggest to just submit the form on click of the checkbox
<input type="checkbox" name="show" value="true" onclick="submit()" />
and then let JSP conditionally display the input fields (just a JSTL example since I don't do Struts)
<c:if test="${param.show == 'true'}">
<input type="text" />
<select />
</c:if>
Update: you've by the way another major problem in the code. You can't compare string values by == in Java code (you can do so in EL only). In Java code you need to use equals() method. Otherwise they will be compared by reference instead of by value. I'd suggest to learn basic Java as well.

Categories