Disabling items in JavaServer Faces - jsf

I’m new in JavaServer Faces.
I have a simply form:
<div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title">#{msgs.leavereply}</h3>
<h1>#{!forumsBean.activeWithProject}</h1>
<h:form>
<h:inputTextarea value="#{forumpostsBean.text}" style="resize:none"/>
<h:commandButton value="#{msgs.add}" action="#{forumpostsBean.addForumpost}"/>
</h:form>
</div>
By clicking command button all it’s fine, executes method forumpostsBean.addForumpost.
But when I modify code to this:
<div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title">#{msgs.leavereply}</h3>
<h1>#{!forumsBean.activeWithProject}</h1>
<h:form>
<h:inputTextarea value="#{forumpostsBean.text}" style="resize:none" disabled="#{not forumsBean.active}"/>
<h:commandButton value="#{msgs.add}" action="#{forumpostsBean.addForumpost}" disabled="#{not forumsBean.active}"/>
</h:form>
</div>
When items not disabled, current page only have refreshed, but method forumpostsBean.addForumpost don’t executes.
In both variants, <h1>#{!forumsBean.activeWithProject}</h1> shows correct value.

You have 2 beans? one called forumpostsBean and another just forumsBean? I can't see if you've got them both but maybe its the main error? as the comment above says, maybe your logic is out of place.
You may want to use rendered="" on the button rather that just disabling it so its not part of the dom at all upon page load and then use an ajax call when you type data in your input field to do partial ajax render the div again and show it. good for testing.

Related

selectBooleanCheckbox 'onBlur' wrongfully called on page load instead of 'onBlur' [duplicate]

I have two image buttons:
<div class="sidebarOptions">
<input type="image" src="images/homeButton.jpg" onclick="#{home.setRendered(1)}"/>
</div>
<div class="sidebarOptions">
<input type="image" src="images/memberButton.jpg" onclick="#{home.setRendered(2)}"/>
</div>
However, the both methods are immediately invoked when the page loads with values 1 and 2. Also when I click it, the both methods are invoked.
How can I achieve the desired functionality of only calling the bean method when the image button is actually clicked?
This approach will not work. You seem to be confusing/mixing the basic web development concepts of the "server side" and "client side" and to be misunderstanding the role of JSF and EL.
JSF is a server side language which runs on the webserver upon a HTTP request and produces HTML/CSS/JS code which get returned with the HTTP response. All EL expressions in form of ${} and #{} will be executed in the server side during generating the HTML output. JavaScript is a client side language which runs on the webbrowser and works on the HTML DOM tree. The HTML onclick attribute should specify a JavaScript function which will be executed in the client side on the particular HTML DOM event.
In order to invoke a JSF managed bean method, you need the action or *listener attribute. JSF provides components to generate the desired HTML and specify the desired ajax actions which would change the server side state. An <input type="image"> can be generated using a <h:commandButton image>. A bean method can be invoked by the action attribute of that component. That component can be ajaxified by embedding the <f:ajax> tag.
So, the following should do it for you:
<h:form>
<div class="sidebarOptions">
<h:commandButton image="images/homeButton.jpg" action="#{home.setRendered(1)}">
<f:ajax execute="#this" render=":sidebar" />
</h:commandButton>
</div>
<div class="sidebarOptions">
<h:commandButton image="images/memberButton.jpg" action="#{home.setRendered(2)}">
<f:ajax execute="#this" render=":sidebar" />
</h:commandButton>
</div>
</h:form>
<!-- The below is just a guess of what you're really trying to achieve. -->
<h:panelGroup id="sidebar" layout="block">
<h:panelGroup rendered="#{home.rendered eq 1}">
Home
</h:panelGroup>
<h:panelGroup rendered="#{home.rendered eq 2}">
Member
</h:panelGroup>
</h:panelGroup>
See also:
Differences between action and actionListener
How to invoke a managed bean action method in on* attribute of a JSF component
How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

Bootsfaces modal not working inside <h:form>

I am new to JSF and I am currently building a web-auction type of application, based on it. I have also used multiple elements from Bootsfaces. What I would like to do is have an inputText where bidders can type their bids and then press a button that will trigger a Bootsfaces modal. Inside the modal, the bidder will have to confirm that he actually wants to bid, by pressing a commandButton that will eventually "submit" his bid. In order for this to work (if I have understood correctly how JSF works), I need the inputText and the commandButton inside the same h:form element. The only problem is that, whenever I put the code of the modal inside the form, the modal doesn't show up when I press the button that triggers it. My code is the following:
<h:form>
<b:inputText class="bid1" value="#{detailedViewBean.current}" placeholder="Type the amount you would like to bid..." style="width: 90%" onfocus="enableButton('atrigger1')" onblur="bidAmount(this.value, '#{detailedViewBean.previous}')"> <!--current highest bid-->
<f:facet name="prepend">
<h:outputText value="$" />
</f:facet>
<f:facet name="append">
<b:buttonGroup>
<a id="atrigger1" class="btn btn-primary" href="#amodal1" data-toggle="modal">Bid!</a>
</b:buttonGroup>
</f:facet>
</b:inputText>
<b:modal id="amodal1" title="Warning!" styleClass="modalPseudoClass">
<p id="amodal1body"> Are you sure ?</p>
<f:facet name="footer">
<b:button value="Close" dismiss="modal" onclick="return false;"/>
<b:commandButton value="Yes, submit my bid!" id="modalbidbutton" type="button" class="btn btn-primary" data-dismiss="modal" data-toggle="modal" data-target="#amodal2"/>
</f:facet>
</b:modal>
<h:form>
Does anyone know why this might happen or how I can correct it?
Moving the <b:modal /> into a form modifies its id. That's an annoying property of the JSF framework: it sees to it that ids are always unique - and of of the measures to achieve that goal is to prepend the form's id to the id of <b:modal >. Most of the time, this works just great, but sometimes you need the HTML id. Your button uses a jQuery expression, so this is one of those times. Adding insult to injury, JSF uses the colon as a separator, and jQuery doesn't cope well with the colon.
Cutting a long story short, I suggest to use the CSS class of the modal dialog instead of the id. You already gave it a pseudo CSS class. This class doesn't bear any layout information. Instead, you can use it in the button:
<a id="atrigger1" class="btn btn-primary disabled"
href=".modalPseudoClass" data-toggle="modal">Bid!</a>
TL;DR: If you run into trouble with id, replace your jQuery expression ("#id") with a CSS pseudo class expression (".pseudoClass").

JSF too many commandLinks (h:form) lead to ViewExpiredException

I am having a JSF application which creates and presents about 50 reports. These reports are rendered PNGs and under the pictures a table is displayed.
This table uses a RichFaces 4 togglePanel with switchType="client". The togglePanel is just for collapsing and expanding the table.
<h:form>
<rich:togglePanel id="#{param.reportWrapper}_togglePanel"
stateOrder="opened,closed" activeItem="opened" switchType="client">
<rich:togglePanelItem name="closed">
<h:panelGroup>
<div class="myclass">
<ul class="container-icons">
<li>
<h:commandLink styleClass="container-max" value="maximieren">
<rich:toggleControl targetPanel="#{param.reportWrapper}_togglePanel" targetItem="#next" />
</h:commandLink>
</li>
</ul>
<h3>My Heading</h3>
</div>
</h:panelGroup>
</rich:togglePanelItem>
<rich:togglePanelItem name="opened">
<h:panelGroup>
<div class="myclass">
<ul class="container-icons">
<li>
<h:commandLink styleClass="container-min" value="minimieren">
<rich:toggleControl targetPanel="#{param.reportWrapper}_togglePanel" targetItem="#prev" />
</h:commandLink>
</li>
</ul>
<h3>Another Heading</h3>
<div class="scrolling-table-content">
<rich:dataTable>
// ...
</rich:dataTable>
</div>
</div>
</h:panelGroup>
</rich:togglePanelItem>
</rich:togglePanel>
</h:form>
The problem is, that I sometimes get a ViewExpiredExceptions when the reports are loaded. My numberOfLogicalViews and numberOfViewsInSession is 14. I dont want to set it to 50, because of memory issues and because it should not be necessary as only one report is really shown at the same time.
I tried to remove the h:form tags, which are seen as logicalView. In my opinion the togglePanel is not the item, which needs the form because it's switch type is client (not server and ajax, which need form tags). But the command link does need the form tag, because if I remove it, an error occurs saying "this link is disabled as it is not nested within a jsf form".
So I tried to replace the commandLink with a commandButton. This worked fine first and the form wasnt necessary anymore. But somehow the behaviour is completely random now. Sometimes the tables can be expanded, sometimes nothing happens when i click the expand button. When i add form tags again, it works fine, but doesnt solve my ViewExpiredException.
Hope, somebody can help me out here...
Thanks for your help!
Buntspecht
If you only need to switch the panel you can use <a4j:commandLink> that lets you limit the execution scope (so it won't submit the whole form). Or you can remove the command components altogether and just use JavaScript API of the togglePanel:
<a onclick="#{rich:component('panelId')}.switchToItem(#{rich:component('panelId')}.nextItem())">Next</a>
Thank you very much for your help Makhiel. I finally managed to solve the problem with the commandButtons solution. I can't explain why, but the IDs of my togglePanelItems got duplicated in the different reports.
Giving every togglePanelItem a unique ID like
<rich:togglePanelItem name="closed" id="#{param.reportWrapper}_opened">
and
<rich:togglePanelItem name="opened" id="#{param.reportWrapper}_closed">
solved the problem...
So now we got rid of all the h:form tags and thus have about 50 logical views less! :)

Confusion JSF Updating Value of Input text in Backing bean

Today, i was solving a small problem in JSF. Actually, i have an InputText on my xhtml page with readyOnly attribute set to true.Requirement was on click of a boolean checkbox, i should make the input text editable, means readyOnly false. The code somewhat seemed like this.
<div class="div-form-col" >
<h:outputLabel value="#{msgs.violationAmount} " for="violationAmt" />
<h:inputText value="#{outpassMBean.violationWebDTO.violationAmount}" id="violationAmt" readonly="true"/>
</div>
<div class="div-form-row">
<div class="div-form-col">
<h:outputLabel value="#{msgs.violationExemptionApplicable} " for="violationExempted" />
<h:selectBooleanCheckbox value="#{outpassMBean.violationWebDTO.violationExemptionApplicable}" id="violationExempted" onchange="makeViolationAmountEditable(this);">
</h:selectBooleanCheckbox>
</div>
</div>
The script of that method was given as below :-
function makeViolationAmountEditable(id){
alert("Ben");
document.getElementById('violationAmt' ).readOnly=false;
alert("Done");
}
Now my first problem was, if i am editing the value in the text field, how i can update the value of violationAmt in backing bean. What can be the best possible way? As i am using PrimeFaces, i came across concept remoteCommand. So here is what i added.
<p:remoteCommand name="makeViolationAmountEditableOnServer" action="#{outpassMBean.makeViolationAmountEditable}" update="amountPanelApplicant"/>
The method at the backing bean level was something like this
public void makeViolationAmountEditable(){
//Set updated value
setUpdatedViolationAmount(violationWebDTO.getViolationAmount());
//Some other code.
}
Problem was that, whenever this code was running, the violation amount in violationWebDTO was the old one, not the one which i was entering after making the input field editable. Though i saw in firebug the updated value was part of request but in the backing bean, however still old value was getting referred. I don't understand why?
My senior told me, you are updating value of readOnly on client side not server side, and updated my code something like this.
<p:outputPanel id="amountPanelApplicant">
<p:outputPanel rendered="#{outpassMBean.violationWebDTO.violationForCmb eq 2 and outpassMBean.violationWebDTO.isViolationExists}">
<p:outputPanel styleClass="div-form twoCol">
<div class="div-form-row">
<div class="div-form-col" >
<h:outputLabel value="#{msgs.violationAmount} " for="violationAmt" />
<h:inputText value="#{outpassMBean.violationWebDTO.violationAmount}" id="violationAmt" readonly="#{outpassMBean.violationAmtEditable}">
</h:inputText>
</div>
<div class="div-form-col">
<h:outputLabel value="#{msgs.outPayTot} " for="totalViolationAmount" />
<h:outputLabel styleClass="readOnly" value="#{outpassMBean.violationWebDTO.totalViolationAmount}" id="totalViolationAmount" />
</div>
</div>
</p:outputPanel>
<p:outputPanel styleClass="div-form twoCol" rendered="#{outpassMBean.outpassApplication.applicationSubType.id eq 2 }" >
<div class="div-form-row">
<div class="div-form-col">
<h:outputLabel value="#{msgs.violationExemptionApplicable} " for="violationExempted" />
<h:selectBooleanCheckbox value="#{outpassMBean.violationWebDTO.violationExemptionApplicable}" id="violationExempted" onchange="makeViolationAmountEditableOnServer();">
</h:selectBooleanCheckbox>
<p:remoteCommand name="makeViolationAmountEditableOnServer" action="#{outpassMBean.makeViolationAmountEditable}" update="amountPanelApplicant"/>
</div>
</div>
</p:outputPanel>
</p:outputPanel>
public void makeViolationAmountEditable(){
if(logger.isDebugEnabled()){
logger.debug("Inside makeViolationAmountEditable...");
}
//setting violation amount editable flag
setViolationAmtEditable(false);
//Preserving original and total amount.
setOriginalViolationAmt(violationWebDTO.getViolationAmount());
setOriginalTotalViolationAmount(violationWebDTO.getTotalViolationAmount());
}
In the above updated code, no javascript called. The readyOnly value is set to true and false from the backing bean itself. After this update, basically the new edited value was updated in the violationWebDTO.
Can someone explain? Why not in the first snapshot? It's not a complete code but i tried to explain the confusion. Any pointers would be helpful.
This is JSF's safeguard against tampered/hacked requests wherein the enduser uses client side languages/tools like HTML or JS to manipulate the HTML DOM tree and/or HTTP request parameters in such way that the outcome of JSF's disabled, readonly or even rendered attribute is altered.
Imagine what would happen if the JSF developer checked an user's role in such a boolean attribute against the admin role like so disabled="#{not user.hasRole('ADMIN')}" and a hacker manipulated it in such way that it isn't disabled anymore for non-admin users. That's exactly why you can only change the mentioned attributes (and the required attribute and all converters, validators, event listeners, etc) on the server side.
This can however be solved in a simpler manner without the need for an additional property, without the <p:remoteCommand> and the additional bean method.
<h:inputText id="violationAmount" ... readonly="#{makeViolationAmountEditable.value}" />
...
<h:selectBooleanCheckbox binding="#{makeViolationAmountEditable}">
<f:ajax render="violationAmount" />
</h:selectBooleanCheckbox>
See also:
Why JSF saves the state of UI components on server?
How does the 'binding' attribute work in JSF? When and how should it be used?.

Action of <h:commandButton> not getting invoked when "disabled=true" is set

I want the Submit button to be enabled when the T&C checkbox is checked. Though my written logic is working alright the action of h:commandButton is not getting invoked even after it is enabled after checking the checkbox. Initially the button is disabled. The code works fine if I remove the disabled="TRUE" attribute but it doesn't serve the purpose. Here is my code :
<script type="text/javascript">
$(document).ready(start);
function start() {
$('.testing').click(
function() {
if ($(document.getElementById('form2:check'))
.is(':checked')) {
$(document.getElementById('form2:saveForm'))
.removeAttr('disabled');
} else {
$(document.getElementById('form2:saveForm')).attr(
'disabled', 'disabled');
}
});
}
</script>
JSP Code:
<h:form id="form2">
<div class="testing">
<h:selectBooleanCheckbox id="check" />
Agree
<li class="buttons ">
<div class="center">
<h:commandButton id="saveForm" styleClass="btTxt submit"
type="submit" value="Submit"
action="#{declarationFormBean.formSubmit}" disabled="true"></h:commandButton>
</div>
</li>
</h:form>
Please help.
That's because you're solely removing the disabled attribute in the JSF-generated HTML representation using JavaScript/jQuery. This doesn't change anything to the disabled attribute in the actual JSF component which is consulted during decoding the action event.
This is actually a Good ThingTM of JSF, because otherwise any hacker would be able to bypass any JSF disabled, readonly and rendered attribute by just manipulating the HTML DOM tree while they are initially used to block them like so rendered="#{request.isUserInRole('ADMIN')}".
You need to enable the button by JSF instead of JS/jQuery.
<h:selectBooleanCheckbox binding="#{check}">
<f:ajax render="saveForm" />
</h:selectBooleanCheckbox>
<h:commandButton id="saveForm" ... disabled="#{not check.value}" />
That's all. No custom JS/jQuery mess necessary, nor any additional JSF bean properties. The above code is complete as-is.
See also:
What is the need of JSF, when UI can be achieved from CSS, HTML, JavaScript, jQuery?

Resources