Requirement is to render a component outside the form after an ajax call. I have tried with the following code but the text was not being rendered.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ads="http://java.sun.com/jsf/composite/components">
<ui:include src="secondfile"/>
<h:panelGroup id="panel1" rendered="#{bean.access}">
Some text
</h:panelGroup>
</ui:composition>
Secondfile:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ads="http://java.sun.com/jsf/composite/components">
<f:ajax render="#form _panel1">
<h:selectOneRadio id="access" value="#{beanTO.access}">
<f:selectItem itemValue="true" itemLabel="yes"/>
<f:selectItem itemValue="true" itemLabel="yes"/>
</h:selectOneRadio>
</f:ajax>
</ui:composition>
I assume that you've changed the default naming container separator character from : to _, otherwise you should have used :panel1 instead of _panel1)
You're trying to ajax-render a component which is by itself conditionally rendered by the server side. This will not work when the component is not rendered in first place. JS won't be able to locate the desired HTML element to update after the ajax response arrives. You need to wrap it in another component which is always rendered to the HTML output and set the rendered condition on the wrapped component.
<h:panelGroup id="panel1">
<h:panelGroup rendered="#{bean.access}">
Some text
</h:panelGroup>
</h:panelGroup>
See also:
Communication in JSF2 - Ajax rendering of content which is by itself conditionally rendered
Related
Let's take the following example:
The composite component is as follows:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<!-- INTERFACE -->
<cc:interface>
<cc:clientBehavior name="click" targets="button" event="click"/>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<span id="#{cc.clientId}">
<h:commandButton id="button" value="Press me">
<f:ajax event="click" listener="#{bean.helloFromComposite()}"/>
</h:commandButton>
</span>
</cc:implementation>
</html>
And the using page is as follows:
<h:form id="form">
<my:button id="my-button">
<f:ajax event="click" listener="#{bean.HelloFromPage()}"/>
</my:button>
</h:form>
Then, when I click on the button the bean logs:
Hello from composite
Hello from page
Hello from composite
Hello from page
Reproduced on Glassfish 4.1.1 with Omnifaces 2.5.1 and Primefaces 6.0.
If I change my using page as follows, then the problem disappears:
<h:form id="form">
<my:button id="my-button">
<f:ajax event="click" listener="#{bean.HelloFromPage()}" execute="#none"/>
</my:button>
</h:form>
When I click on the button the bean now logs:
Hello from composite
Hello from page
I have two questions:
Is it a known behavior?
Is the sequence "Hello from composite", "Hello from page" by design? It's fine by me, as in my opinion the ajax behavior inside the composite is more specific (and should be executed first) than the ajax behavior specified in the using page.
Edit:
I can reproduce the problem in a very simple way, as follows:
<h:form>
<h:commandButton>
<f:ajax event="click" listener="#{bean.helloOne()}"/>
<f:ajax event="click" listener="#{bean.helloTwo()}"/>
</h:commandButton>
</h:form>
Solved by adding an execute #none attribute in the second AJAX call:
<h:form>
<h:commandButton>
<f:ajax event="click" listener="#{bean.helloOne()}"/>
<f:ajax event="click" listener="#{bean.helloTwo()}" execute="#none"/>
</h:commandButton>
</h:form>
Could there be a confusion between the button is 'clicked' and the button is 'executed'?
I'm using JSF2.1.
What is the difference beetween execute="#form" and this.submit() in the code below?
<f:ajax execute="#form" render="#form"/>
and:
<h:form onkeypress="if (event.keyCode == 13) this.submit();">
The former seems to submit the values and re-render the form, while the latter causes a page refresh. Is there any way to use ajax when the enter key is pressed in the form? I'm trying to detect the enter key being pressed in an inputText box. I've tried things like this:
<h:inputText value="#{a.name}" >
<f:ajax execute="#this" />
</h:inputText>
but this just causes the values to be submitted when you click on something else (after valueChange).
In order to answer your question's title, the difference between them is that a form submit sends the whole form and reloads the view, while an ajax form execution also submits the whole form, but using an ajax request which can be used to render only a specific part of the view before response happens.
Regarding to your question content, the form submit by pressing the Enter key is implemented in the major browsers for single input forms. There's no need of javascripting the onkeypress event, as the browser will detect that and send the form by default.
So the next code piece has the same result for server side, either pressing the Send button or the Enter key: The value attribute being set. Note that in the second form, where the <h:inputText /> has an ajax behaviour, the h:outputText value is also refreshed (even not being specified a render attribute) when hitting the Enter key, that's because of the full submit request being prioritized over the ajax request and the whole page being reloaded. Only Google Chrome seems to tell about that conflict: httpError:The Http Transport returned a 0 status code. This is usually the result of mixing ajax and full requests.
Full request:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}" />
<h:commandButton value="Send" />
</h:form>
</body>
</html>
Ajax request:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}">
<f:ajax />
</h:inputText>
<h:outputText value="Echo: #{bean.value}" />
</h:form>
</body>
</html>
When the form has more than an input field you can use such a javascript verification for sending the form if there's no any submit button, using full submit request. If there's, doing that is unecessary.
Finally, if you want to perform an ajax request when hitting the key and update model values, use onkeypress attribute:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head />
<body>
<h:form>
<h:inputText value="#{bean.value}"
onkeypress="if (event.keyCode == 13) {onchange(); return false; }">
<f:ajax render="echo" />
</h:inputText>
<h:inputText value="#{bean.value2}" />
<h:outputText id="echo" value="Echo: #{bean.value}" />
</h:form>
</body>
</html>
Remind that it's advisable to use a submit button for plain accessibility matters.
See also:
JSF 2.0: ajax request when press ENTER
Jsf calling bean method from input text when pressing enter
I have a grid group that should be rendered when change the value of the selectOneMenu. I have attached a valueChangeListener to the selectOneMenu and it access succefully the function assigned to it , but the html component does not rerender. the strange thing that the flag the determines the rendering is called anyway.
<h:selectOneMenu value="#{channelsAdmin.profileID}" id="profileDrp" valueChangeListener="#{channelsAdmin.setProfileInit}">
<f:selectItems value="#{channelsAdmin.profiles}" var="Profile"
itemLabel="#{Profile.profileName}"
itemValue="#{Profile.profileId}" />
<f:ajax execute="#this" immediate="true" render="pnl"></f:ajax>
</h:selectOneMenu>
<h:panelGroup id="pnl" rendered="#{channelsAdmin.ccpAuthPanelFlage}">
<h:inputText id="sest" value="hew">
</h:inputText>
</h:panelGroup>
Bean:
public void setProfileInit(ValueChangeEvent e) {
ccpAuthPanelFlage=true;
ccpPurchPanelFlage=true;
}
The <f:ajax render="pnl"> works roughly as follows:
When the ajax response is arrived, obtain the update element with id="pnl" from XML response.
Now obtain the element with id="pnl" from HTML document by document.getElementById().
Replace its contents with the update element from XML response.
In your particular case, step 2 failed because there's no such element in the HTML document. It doesn't exist in the HTML document because it's never been rendered in first place.
You need to make sure that <f:ajax render="..."> refers an element which is always rendered so that JavaScript can find it by document.getElementById() in order to replace its contents.
<h:selectOneMenu value="#{channelsAdmin.profileID}" id="profileDrp" valueChangeListener="#{channelsAdmin.setProfileInit}">
<f:selectItems value="#{channelsAdmin.profiles}" var="Profile"
itemLabel="#{Profile.profileName}"
itemValue="#{Profile.profileId}" />
<f:ajax execute="#this" immediate="true" render="pnl"></f:ajax>
</h:selectOneMenu>
<h:panelGroup id="pnl">
<h:panelGroup rendered="#{channelsAdmin.ccpAuthPanelFlage}">
<h:inputText id="sest" value="hew">
</h:inputText>
</h:panelGroup>
</h:panelGroup>
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
My form contains a dropdown list inside a ui:repeat component. When any list item is selected, an f:ajax call triggers a refresh of both dropdown list and several other components inside ui:repeat . Im struggling to work out the correct id format for the f:ajax render="???????" (see facelet view below). Any help would be appreciated.
Ive supplied raw source view of the rendered screen (actual JSF ids) and a facelet view showing the same components as coded.
Browser Source View
<form id="GeneralMedicalHistory" name="GeneralMedicalHistory" method="post" action="..."
<span id="GeneralMedicalHistory:GeneralMedicalHistory_P">
<span id="GeneralMedicalHistory:medhist">
<table border="0" class="table_form">
<select id="GeneralMedicalHistory:RPTK:0:MedicalCondition" name="GeneralMedicalHistory:RPTK:0:MedicalCondition" > ---> TARGET ID (UI:REPEAT)
Facelet view
<h:form id ="GeneralMedicalHistory">
<h:panelGroup id="GeneralMedicalHistory_P">
<h:panelGroup id="medhist">
<ui:repeat value="#{f.repeatingItemGroups['MedicalHistory'][1]}" var="repeatKey" id="RPTK" >
<h:commandLink action="remove_repeating_ig" rendered="${f.items[removeOid].isNew and repeatKey != '1'}"></>
<table border="0" class="table_form">
<h:selectOneMenu value="${f.items[oid].value}" id="MedicalCondition" >
<f:selectItems value="${f.items[oid].codeListItems}"/>
<f:ajax render="?????????" event="click" listener="#{f.clearModelValuesViaAjax}" />
</h:selectOneMenu>
</table>
</h:panelGroup>
</h:panelGroup>
</h:form>
Ive tried the following but none have worked...
f:ajax render="GeneralMedicalHistory:RPTK:0:MedicalCondition"
f:ajax render=":GeneralMedicalHistory:RPTK:0:MedicalCondition"
f:ajax render="GeneralMedicalHistory_P:medhist:RPTK:0:MedicalCondition"
f:ajax render=":GeneralMedicalHistory_P:medhist:RPTK:0:MedicalCondition"
f:ajax render="GeneralMedicalHistory:GeneralMedicalHistory_P:medhist:RPTK:0:MedicalCondition"
f:ajax render=":GeneralMedicalHistory:GeneralMedicalHistory_P:medhist:RPTK:0:MedicalCondition"
The <ui:repeat> is by itself a NamingContainer. You can just reference a client ID relative to the <ui:repeat> itself.
Your code example is confusing, you're basically attempting to perform render="#this", so here's a different and more elaborate example wherein another menu component and some input component are been ajax-updated on change of the current menu:
<ui:repeat ...>
<h:selectOneMenu ...>
...
<f:ajax ... render="otherMenu someInput" />
</h:selectOneMenu>
<h:selectOneMenu id="otherMenu" ... />
<h:inputText id="someInput" ... />
</ui:repeat>
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
The code below is the tabView, followed by the structure of the loaded page. For the commandButton, I have tried actionListener, different combinations of render and update referencing the target inputtextarea (req) explicitly, etc. The action works fine when the form runs in its own page (not within a tab).
In the "preRenderView" event, I initialize data structures, which are populated when the form displays. Problem is when I click on the Preview button. Normally the action fires, the handling method assembles the data for display in the preview inputextarea (req), and it's displayed.
Strangely, when I click the button, the action is NOT called, although there is activity calling my other tabs' loadReqEvents, and in the outer page hosting the tabView. I suspect this is a request-response nuance of JSF that I'm unaware of. Thanks for help.
<p:tabView id="tbv" dynamic= "true" activeIndex="#{sessionController.activeTab}" styleClass="tabview-style">
<p:tab id="rtmTab" styleClass="tab-style" title="RTM" closable="false" titletip="Requirements Traceability Matrix">
<ui:include src="url(./../rtm.xhtml"/>
</p:tab>
<p:tab id="composeTab" styleClass="tab-style" title="#{sessionController.composeTabTitle}" rendered="#{sessionController.crudTabRendered}" closable="false" titletip="Composition Form">
<ui:include src="url(./..#{sessionController.composeUrl}.xhtml"/>
</p:tab>
<p:tab id="objTab" styleClass="tab-style" title="Object / Data Model" closable="false" titletip="Object and Data Model View">
<ui:include src="url(./../objView.xhtml"/>
</p:tab>
</p:tabView>
</p:layoutUnit>
<p:layoutUnit id="formLayout" position="center" gutter="0" styleClass="form-layout">
<h:form>
<f:event listener="#{attrDefController.loadReqEvent}" type="preRenderView"></f:event>
<p:panel style="background-color:rgb(222,231,254);width:925px;height:98%;margin-top:-4px;margin-left:-8px">
<h:panelGrid columns="7" style="margin-right:-8px" cellpadding="2">
<h:commandButton id="preview" value="Preview" action="#{attrDefController.previewReqAction}" style="width:100px; margin-top:2px">
<f:ajax execute="#form" render="req"/>
</h:commandButton>
</h:panelGrid>
</p:panel>
</h:form>
</p:layoutUnit>
Without seeing the markup for where the component req is declared, I assume that it exists in one of the xhtml files specified in the ui:include.
The problem is that the render attribute of the f:ajax is specifying an id which does not exist on the page. The reason for this is that is that the components client ID will be prefixed with the client id of its parent UINamingContainer.
Not all JSF components are a UINamingContainer, form definitely is which is why you will typically see the ID of the form prefixed to the client id of a component. Eg:
<h:form id="formone">
<h:outputText id="textComponent" value="YO" />
<h:commandButton ...>
<f:ajax update="textComponent" />
</h:commandButton>
</h:form>
<h:form id="formtwo">
<h:commandButton ...>
<f:ajax update=":formone:textComponent" />
</h:commandButton>
</h:form>
In the above example the client ID of textComponent is actually formone:textComponent. Now the command button in the example above can still reference it by its Actual ID because it happens to be in the same UINamingContainer as its sibling component.
The commandButton in the other form however must access it by its full client id because it is not a sibling of textComponent. It does this by prefixing the client ID with the universal selector : and then following that with the entire client ID of the textComponent.
Now what does this have to do with your problem?
The PrimeFaces TabView component happens to be a UINamingContainer as well.
So that means that to Ajax render the component with ID req you will need to specify an ID for your form and call it in this way...
render=":formid:tbv:req"
I hope this makes sense.