Show/Hide RichFaces component onclick client-side? (without AJAX) - java

I'm looking for a way to show/hide an arbitrary RichFaces component. In this case, I have a <rich:dataTable> that contains several rows. Each row needs to have it's own, independent Show/Hide link, such that when you click "Show details", two things happen:
The "Show details" link is re-rendered as "Hide details"
The associated detailsColumns should become visible (starting from a state of rendered="true" but style="display: none;").
I don't want to write my own JavaScript functions if it's not absolutely necessary. I also don't want to have a server-side bean keep track of which detailColumns are being displayed, and subsequently re-render everything over AJAX: this should be purely client-side behavior. I'm not sure how to accomplish that.
The following pseudo-code (hopefully) illustrates my goal:
<rich:column>
Show details
Hide details
</rich:column>
<rich:column>
<h:outputText value="#{thisRow.someData}" />
</rich:column>
<rich:column id="detailsColumn" colspan="2" breakBefore="true">
<h:outputText value="#{thisRow.someMoreData}" />
</rich:column>

To the point, you need to grab the generated HTML element from the DOM in JavaScript and then toggle its CSS display property between block and none. As far as I know, RichFaces doesn't provide out-of-the-box scripts/facilities for this, but it is basically not that hard:
function toggleDetails(link, show) {
var elementId = determineItSomehowBasedOnGenerated(link.id);
document.getElementById(elementId).style.display = (show ? 'block' : 'none');
}
with
<h:outputLink onclick="toggleDetails(this, true); return false;">show</h:outputLink>
<h:outputLink onclick="toggleDetails(this, false); return false;">hide</h:outputLink>

Related

Not able to render the parent panel group component with <p:ajax>

I am using primefaces autocomplete in my application to suggest userIds to the User.Once user enters three characters into the Autocomplete textbox my UserIds list will be suggested to the user to Autocomplete. As soon as user selects userId from List, I am updating the User First and Last name in the Output Text in the following format John Doe(jd123) with a Delete button beside to this name. As shown in comments in the code first ajax request is perfectly working fine.But When I am trying to delete name that I am printing using <h:outputText/> I am getting an error which is
javax.faces.FacesException: Cannot find component with identifier
"items" referenced from "j_idt34:0:imgid".
My Code :
<h:outputLabel value="Select user" for="acMinLength" />
<p:autoComplete id="acMinLength"
minQueryLength="3"
value="#{autoCompleteBean.txt2}"
completeMethod="#{autoCompleteBean.complete}">
<p:ajax event="itemSelect"
listener="#{autoCompleteBean.handleSelect}"
update="items"/> // First Ajax request perfectly working fine
</p:autoComplete>
<h:outputLabel value="selectedUsers" for="acMinLength" />
<h:panelGroup id="items">
<ui:repeat value="#{autoCompleteBean.printId}" var="item">
<h:outputText value="#{item}"/>
<h:graphicImage name="delete.png" library="images" id="imgid">
<p:ajax event="click"
listener="#{autoCompleteBean.updateList}"
update="items"/> // This is where i am getting exception
</ui:repeat>
<h:panelGroup>
I know I can update the parent component with child Ajax request. But I don't know what I am doing wrong.
it should be safer to update the h:form component. I'm not sure you can update every h: component by id. If you open the resulting xhtml and try checking the actual id path of the children components, you will see that the don't include the ids of all of their parent's component. Some id's are skipped
However, you can try this
update=":#{p:component('items')}"
Hope it helps
After a rigorous search I tried the answer posted by andre here(Primefaces - Cannot find component with identifier outside the datatable) and hurray it's working.
like this
update="#([id$=items])"

onChange event not firing in IE8 when switching active Window

I have a weird problem, which is probably a bug in IE8, but I am seeking for a workaround.
Description of the UI:
I have a form that displays many rows. When the user enter a value in one of the row, it will perform some basic validation and then it will add a "delete" link next to it. (the goal is to delete the entered row).
Description of the problem:
User enter some data
User switch window (go in any other IE tab or even switch to another software, like notepad)
come back to IE, and enter another row
--> The "onchange" event is not fired when the user clicks elsewhere.
This works fine with Chrome or other browsers (the event is fired normally even if we switch window).
Workaround
- before switching to another software, if the user just press tab or click in another cell, the "onchange" event works as expected.
Anybody got a similar problem, or know another method that would do simiar behavior and work in all browsers?
Here is the code:
<rich:column>
<h:inputText id="batchSaid" value="#{currentBatch.batchSaid}" onkeypress="enableValidateitemsButton(this);"
onblur="validateCase(this,'MYVALUE');enableValidateitemsButton(this);">
<a4j:support event="onchange" process="batchAdd" action="#{itemsPageFormImpl.enableValidateBtnDisableActivateBtn(currentBatch, tRowId)}"
reRender="deleteBatchLink, deleteBatchLinkId" ajaxSingle="true"/>
</h:inputText>
</rich:column>
<rich:column id="deleteBatchLinkId">
<div align="right">
<a4j:commandLink id="deleteBatchLink" style="font-weight:bold;" value="Delete" action="#{itemsPageFormImpl.deletBatch}" reRender="batchdataTable"
rendered="#{currentBatch.showBatchRowDelBtn}" ajaxSingle="true">
<f:setPropertyActionListener target="#{itemsPageFormImpl.deleteBatchId}" value="#{currentBatch.batchId}" />
</a4j:commandLink>
</div>
</rich:column>
The problem is with the deleteBatchLink not being displayed.
We finally never found a solution to this. The users uses the workaround.

JSF f:ajax and IE 8

I encountered with problem: in IE8 don't work event in f:ajax and don't update other components after change value.
<h:selectBooleanCheckbox id="someId"
value="#{someBean.showEmpty}"
title="#{i18n['button.showEmpty']}">
<f:ajax event="change"
listener="#{someBean.changeShowEmpty}"
execute=":someForm #form" render=":messages :someForm #form" />
</h:selectBooleanCheckbox>
In Chrome, Opera, Firefox - it works.
Thanks for the help.
That's indeed "expected" behaviour for MSIE. It will only work on 2nd change and forth, because MSIE thinks that the 1st click is in essence not a change. You should be listening on the click event instead. That's also exactly what the <f:ajax> already by default does for a <h:selectBooleanCheckbox>. Just remove the event attribute altogether.
<f:ajax listener="#{someBean.changeShowEmpty}"
execute=":someForm #form" render=":messages :someForm #form" />
The <f:ajax event> defaults to "valueChange" in UIInput components and defaults to "action" in UICommand components. In UIInput components which generate radio button or checkbox, it will then generate onclick. In other UIInput components (text fields, textarea, dropdowns, etc) it will generate onchange.
Unrelated to the concrete problem, an other <h:form> can not be processed in contrary to what you seem to think in execute attribute, simply because its values are not submitted along with the submit of the current form. But that's another story.

a4j: outputPanel ReRender does not work

I have a an a4j:outputPanel that is rendered based on some boolean condition:
<a4j:outputPanel id="someDisplayRegion" rendered="#{doc.ready &&amp someClass.someBooleanMethod}">
// bunch of stuff //
</a4j:outputPanel>
Then on the same .xhtml page, I have a drop-down menu and selecting one of its options should reRender the above region:
<rich:dropDownMenu>
<f:facet name="label">
<a4j:commandLink styleClass="btn-pulldown">
<span><h:outputText value="Export"></h:outputText></span>
<span class="opener"></span>
</a4j:commandLink>
</f:facet>
<rich:menuItem submitMode="none">
<s:link
rendered="#{someOtherBooleanMethod}"
value="#exportDoc"
action="#{runSomething.exportDoc()}"
reRender="someDisplayRegion"
target="downloadfile"
><s:conversationId /></s:link>
</rich:menuItem>
</rich:dropDownMenu>
However, when I click on the menu item from the drop-down menu, it does not go into someClass.someBooleanMethod and thus, does not re-render someDisplayRegion. Am I doing something wrong?
Consider this point of the RichFaces documentation:
As with most Ajax frameworks, you should not attempt to append or
delete elements on a page using RichFaces Ajax, but should instead
replace them. As such, elements that are rendered conditionally should
not be targeted in the render attributes for Ajax controls. For
successful updates, an element with the same identifier as in the
response must exist on the page. If it is necessary to append code to
a page, include a placeholder for it (an empty element).
So add a wrapper around your outputPanel and target the wrapper in the reRender attribute.
<a4j:outputPanel id="wrapper">
<a4j:outputPanel id="someDisplayRegion" rendered="#{doc.ready && someClass.someBooleanMethod}">
// bunch of stuff //
</a4j:outputPanel>
</a4j:outputPanel>
<s:link reRender="wrapper" [...] />
s:link doesn't have reRender attribute, it's only available on RichFaces components.
rich:menuItem and s:link aren't the best of friends. (especially not in earlier version of RichFaces).
Is there a specific reason why you want to use s:link here ?
Putting the action and the reRender on the menuItem itself should work fine.
I don't understand why you think clicking on the menu item should go into someClass.someBooleanMethod and not into runSomething.exportDoc(). At what point are doc.ready and someClass.someBooleanMethod being set to true? You might put a debugging statement in your code that verifies these are being set to true. If they are set to true and your a4j:outputPanel is still not rendering then you have a problem. I use the s:link as you do here and it works, but I remember having to fiddle with it. Make sure the action fired in the s:link returns a String. "actions" have to return strings that can be used for navigation though in my case the page navigates to itself (like yours).

I need a button that performs an action but doesn't trigger validation or refreshes the page(JSF 2.0)

I need you to recommend me a JSF component that can help in the following scenario(I will first paste an image that will help me explain):
This page that you see in the image is a registration page, each of the panels have different fields and gadgets, when the register button is clicked, a new user is saved into the database.
The problem i have is in the show buttons. The buttons on top of each panel when clicked should display one panel and hide the other, but they must not trigger the field validation.
I use field validation by the attribute "validator"(in combination with a backing bean method) that most of JSF input fields have.
Currently everything that you see there is inside one h:form.
-what should i do to display a panel and hide the other without triggering the validation of the panel that is hiding?
-Is there another alternative to the h:commandLink or h:commandButton(they trigger the validation)?
-Putting each panel in a different h:form can do the trick?(Is that permited?)
-What do you think would be the best approach?
Use p:tabView Of primefaces, then put your contents(registration panels) in separate tab, use separate form for both of the tab, it will solve your problem....
e.g.
<p:tabView>
<p:tab title="panel1">
<h:form id="form1" prependId="false">
<h:inputText label="Sample Label"/>
<p:commandButton value="register"/>
</h:form>
</p:tab>
<p:tab title="panel2">
<h:form id="form2" prependId="false">
<h:inputText label="Sample Label"/>
<p:commandButton value="register"/>
</h:form>
</p:tab>
</p:tabView>
-what should i do to display a panel and hide the other without triggering the validation of the panel that is hiding?
Use two h:form
s there another alternative to the h:commandLink or h:commandButton(they trigger the validation)?
to make POST you must only use them
I would have used rich:modalpanel for this purpose
For the panel's toggle, Why don't you use JavaScript?
<h:commandButton value="Show panel 1" onclick="$('#panel1').hide();$('#panel2').show();return false;"/>
The return false will restrict the page from submitting, hence page won't refresh and since no data is posted back to server, validation phase will never execute.
Bottom line : IMHO this can be handled at client side itself.
You are aware of the immediate attribute, allowing to refresh without changing data.
Unfortunately it doesn't remember changes entered, so you might end up in the validation explicitly being done in your action instead of by JSF itself.

Categories

Resources