Command Link under tab using Ajax Primefaces - ajax

I know that this question may be similar to this one but I didn't understand the answer at all.
I am using a full page layout, in the left layout I have some nested accordion panels, tabs and command links. I want this links to update center layout content form.
Left Layout:
<h:form>
<p:accordionPanel>
<p:tab title="Parent Tab">
<p:accordionPanel>
<p:tab title="Child Tab">
<p:commandLink value="link" update=":contentform" />
</p:tab>
</p:accordionPanel>
</p:tab>
</p:accordionPanel>
</h:form>
Center Layout:
<h:form id="contentform">
<ui:include src="#{layoutUI.viewId}" />
</h:form>
And a simple explanation will help cause the similar question lacks in that :(

The proper use of the built in Ajax functionality of the p:commandLink component is to specify that the link will invoke an Ajax call with the ajax attribute.
<p:commandLink value="link" ajax="true" update=":contentform" />
Using the : in front will signify that you are looking for the ID of a component on the ViewRoot rather than its direct Naming Container so this is correct. The only thing missing is the ajax attribute.

Related

How to dynamically show/hide components under p:tab via ajax?

Forgive me I am not even sure my question is correctly stated. I am trying to unravel relationship between p:tab and h:panelGroup. I have very shallow understanding of JSF. I have following code.
<p:tabView id="view">
<p:tab id="A">
...
<p:ajax event="change" update="C,D" listener="#{bean.captureValue}"/>
</p:tab>
<p:tab id="B" titleStyleClass="x">
<h:panelGroup id="C">
<h:panelGroup rendered="#{bean.checkValue eq 'Yes'}"/>
<f:facet name="title"><table>...</table></f:facet>
<div>....</div>
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="D">
<h:panelGroup rendered="#{bean.checkValue eq 'No'}"/>
<f:facet name="title"><table>.....</table></f:facet>
<div>....</div>
</h:panelGroup>
</h:panelGroup>
</p:tab>
</p:tabView>
So within component id="A", a user selects a value from drop down menu, bean captures it and dynamically show or hide component id="C" or "D" based on the value.
First time try, I didn't have any h:panelGroup tags. I used rendered attribute directly from p:tab component however I realized that unless I refresh the entire page, the bean.checkValue wouldn't know latest value captured. By reading many articles in this forum, I realized I have to wrap it with h:panelGroup which in turn worked by showing either h:panelGroup "C" or "D" based on the value selected from p:tab tag with id="A".
However the contents of f:facet tag is not visible anymore. It has html table tag which contains h:outputText with static value and p:graphicImage. I am not sure why and hope someone can solve this mystery.
Update:
Thanks to Arthur. I was able to fix the issue with his help. I paste here code that performs expected output.
<p:tabView id="view">
<p:tab id="A">
...
<p:ajax event="change" update="view" listener="#{bean.captureValue}"/>
</p:tab>
<p:tab id="B" titleStyleClass="x">
<f:facet name="title">
<ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
<table>...</table>
</ui:fragment>
</f:facet>
<ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
<div>...</div>
</ui:fragment>
<f:facet name="title">
<ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
<table>...</table>
</ui:fragment>
</f:facet>
<ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
<div>...</div>
</ui:fragment>
</p:tab>
</p:tabView>
Facets are representing a named section within a container component. Container for your facets are in both cases <h:panelGroup> and this component doesn't define any facet which you could use. As you don't provide in your sample code any name for the facet (which is mandatory) I only assume that maybe you would like to use a title facet for a tab, as <p:tab> component define facet named "title". Then it should look like
<p:tab id="B">
<f:facet name="title" >
<h:outputText value="Test1" rendered="#{bean.checkValue}"/>
<h:outputText value="Test2" rendered="#{!bean.checkValue}"/>
</f:facet>
</p:tab>
, so you implement rendering logic inside facet value (you decide which title would be displayed. This logic could be also moved to backing bean. Keep in mind that in primefaces sometimes components doesn't handle very well and you could try then use them as an attribute instead of facets as stands in this post
It is also possible that you misunderstand meaning of facets. The best way to explain them are the facets defined i component. Authors of this component wanted to provide for users possibility to define header and footer of datatable. Then you, as a jsf user can compose header for instance, from other different components. You could also check this post where facets are also explained.
One more thing to add is that using <h:panelGroup rendered="#{bean.checkValue}"/> for render logic is considred as bad pattern as it is going to produce a <span> element in your code. Instead you should use <ui:fragment rendered="#{bean.checkValue}"/> which is intended for rendering logic and it won't produce any additional html code

f:ajax render form component

I want to render a single component (h:selectManyCheckbox) inside a form based on a check-box that I select or not.
<h:form>
<h:selectBooleanCheckbox value="#{bean.var}">
<f:ajax event="click" render="employeeCheckboxes" />
</h:selectBooleanCheckbox>
<h:selectManyCheckbox
id="employeeCheckboxes"
value="#{bean.checkboxes}"
rendered="#{var}">
</h:selectManyCheckbox>
</h:form>
However, the component isn't re-rendered on selecting or deselecting the check-box. I can however re-render the whole form but I don't want that.
You can't reference a component in <f:ajax render> which is in first place never rendered in HTML output. The <f:ajax render> uses under the covers JavaScript document.getElementById() to find the HTML element in order to update it with the new HTML structure from the ajax response. However, if a JSF component is in first place never rendered in HTML output, then JavaScript can't find it anywhere either.
You need to wrap it in another component which is always rendered.
<h:form>
<h:selectBooleanCheckbox value="#{bean.var}">
<f:ajax render="employeeCheckboxesGroup" />
</h:selectBooleanCheckbox>
<h:panelGroup id="employeeCheckboxesGroup">
<h:selectManyCheckbox
id="employeeCheckboxes"
value="#{bean.checkboxes}"
rendered="#{bean.var}">
</h:selectManyCheckbox>
</h:panelGroup>
</h:form>
(note that I removed event="click" as it's the default already)
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
Hi i think you missed managed bean name in
rendered attribute
of checkbox tag.

JSF2: Form ajax action makes another form's view state to be lost

I have a simple page consisting of two forms. They cannot be displayed simultaneously (one toggles the other). Here is the code:
<h:body>
<ui:composition template="/elements/templateWithMenu.xhtml">
<ui:define name="content">
<p:dialog id="question1DialogId" widgetVar="question1Dialog" resizable="false" closable="false" visible="true">
<h:panelGroup id="questionStep1Group">
<h:form id="questionStep1Form" rendered="#{newPoll2.displayQuestionStep1}">
<h:commandLink value="next" action="#{newPoll2.questionStep1Completed()}" class="btn" >
<f:ajax execute="#form" render=":questionStep2Form :questionStep1Group :questionStep2Group"/>
</h:commandLink>
</h:form>
</h:panelGroup>
<h:panelGroup id="questionStep2Group">
<h:form id="questionStep2Form" rendered="#{newPoll2.displayQuestionStep2}">
<h:commandLink value="cancel" action="#{newPoll2.questionStep2Cancelled()}" class="btn" >
<f:ajax execute="#form" render=":questionStep1Form :questionStep1Group :questionStep2Group" />
</h:commandLink>
</h:form>
</h:panelGroup>
</p:dialog>
</ui:define>
</ui:composition>
</h:body>
questionStep1Completed() and questionStep2Cancelled() simply toggle the booleans used in rendered attribute.
The problem is with the view states. When the page is first loaded, clicking on "next" will work, and it will be replaced with the "cancel" link. But when I click on the "cancel" link, it needs to be clicked twice in order for it to be replaced with with the "next" link. I can see that the first click makes the request with no view state, and the second (successful) one makes a request with it.
I saw this question, and this link, and as you can see, I've added form ids in the render attribute, but it still doesn't work. Any ideas?
Thanks
You're conditionally rendering the forms themselves and hence the other form isn't physically available in the HTML DOM tree at the moment the ajax request is been prepared. If you wrap the form's content in another <h:panelGroup> and move the rendered attribute to there, then it ought to work.

How to inject one JSF2 page into another with jQuery's AJAX

I'm using jQuery's .load function to load one JSF page into another.
This works really well until the loaded JSF page uses some AJAX functionality. When this happens, the parent JSF page's AJAX stops working. In fact, after the two pages are combined whichever page has its AJAX called next is the one that continues to work. The other page stops working. If I use the parent page first, the child breaks. If I use the child first, the parent breaks.
Am I doing something wrong? I'm guessing JSF isn't designed for this sort of behaviour and that's fine but then how do I go about doing what I want?
Basically, we have a report page. When the user clicks the link to a report we would like the report to load dynamically into the existing page. That way, the user doesn't experience a page refresh. It's a pretty slick behaviour BUT obviously isn't ideal due to the pages breaking.
I suppose I could do this with a page that contains every report in an outputpanel and then determine which one is rendered based on a value in the backing bean but I can see lots of occasions where I'd like to be able to "inject" one page into another (for dynamic dialogs for instance) and it would suck to have to keep everything in one giant template.
Has anyone else come across this sort of problem? How did you solve it?
Do not use jQuery.load(). It does not take JSF view state into account at all, so all forms will fail to work. Rather make use of <f:ajax> and rendered attribute instead. Here's a basic example:
<h:form id="list">
<h:dataTable value="#{bean.reports}" var="report">
<h:column>#{report.name}</h:column>
<h:column>
<h:commandLink value="Edit" action="#{bean.edit(report)}">
<f:ajax render=":edit" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
<h:form id="edit">
<h:panelGrid columns="3" rendered="#{not empty bean.report}">
<h:outputLabel for="name" value="Name" />
<h:inputText id="name" value="#{bean.report.name}" required="true" />
<h:message for="name" />
...
<h:panelGroup />
<h:commandButton value="save" action="#{bean.save}" />
<h:messages globalOnly="true" layout="table" />
</h:panelGrid>
</h:form>
You can if necessary split off the content into an <ui:include>.

JSF form post with AJAX

I want the following form to use AJAX. So the comments are shown after clicking the command button and without reloading the page. What needs to be changed, using Java Server Faces 2.0?
Functionality: This form provides an inputText to define a topic. After pressing the commandButton, it is searched for comments regarding this topic. Comments are shown in a dataTable, if there are any. Otherwise Empty is shown.
<h:form id="myForm">
<h:outputLabel value="Topic:" for="topic" />
<h:inputText id="topic" value="#{commentManager.topic}" />
<h:commandButton value="read" action="#{commentManager.findByTopic}" />
<h:panelGroup rendered="#{empty commentManager.comments}">
<h:outputText value="Empty" />
</h:panelGroup>
<h:dataTable
id="comments"
value="#{commentManager.comments}"
var="comment"
rendered="#{not empty commentManager.comments}"
>
<h:column>
<h:outputText value="#{comment.content}"/>
</h:column>
</h:dataTable>
</h:form>
You need to tell the command button to use Ajax instead. It's as simple as nesting a <f:ajax> tag inside it. You need to instruct it to submit the whole form by execute="#form" and to render the element with ID comments by render="comments".
<h:commandButton value="read" action="#{commentManager.findByTopic}">
<f:ajax execute="#form" render="comments" />
</h:commandButton>
Don't forget to ensure that you've a <h:head> instead of a <head> in the master template so that the necessary JSF ajax JavaScripts will be auto-included.
<h:head>
...
</h:head>
Also, the element with ID comments needs to be already rendered to the client side by JSF in order to be able to be updated (re-rendered) by JavaScript/Ajax again. So best is to put the <h:dataTable> in a <h:panelGroup> with that ID.
<h:panelGroup id="comments">
<h:dataTable rendered="#{not empty commentManager.comments}">
...
</h:dataTable>
</h:panelGroup>
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
You need to modify your button:
<h:commandButton value="read" action="#{commentManager.findByTopic}">
<f:ajax render="comments" />
</h:commandButton>
This means, when the button is clicked, the action is executed, and the dataTable will be rendered and updated. This only works if the backing bean is at least view-scoped.

Resources