How to reRender an inputText generated dynamically by a dataTable using Ajax - ajax

I'm using here in my project JSF 1.2 and the Tag <a4j:support> .
Well, i'm using here a <h:dataTable /> to print on the screen a list of financial expenses, where it's possible for the user to insert new expenses or edit the existed expenses at anytime, the value of these expenses fields (amount, balance, value) are being shown in inputTexts components.
As i'm using a <h:dataTable /> the inputTexts of it are generated automatically, so it creates dynamical inputTexts with dynamical ids. I took a look at the html source code of the page and the pattern JSF uses to generate the ids in a dynamically way is this:
id="formTemplate:tableForm:0:inputTextValue" ;
id="formTemplate:tableForm:1:inputTextValue" ;
id="formTemplate:tableForm:2:inputTextValue"
And in the xhtml page the code i used with the dataTable is this:
<h:inputText id="inputTextValue" value="#{item.value}" label="Value" styleClass="field" size="9" readonly="true" dir="RTL" style="font-size:12px;width:170px">
My business rule works like that: When the user types something in the inputTextBalance it calls the event onBlur where it automatically inserts an other value in the field "value", but to update this inputTextValue i need to do a reRender in my panel (panelDataTable), so it reRender the whole dataTable (dataTable is inside the Panel).
<h:inputText id="inputTextBalance" value="#{item.balance}" dir="RTL">
<f:convertNumber currencyCode="BRL" type="currency" />
<a4j:support event="onblur" reRender="panelDataTable" ajaxSingle="true" action="#{expenses.update}"/>
</h:inputText>
Now comes the trouble, what i need to do is to reRender only the inputTextValue instead of the panel, but these fields are generated dynamically and i can't get there ids. Like i said before, this is the pattern that JSF uses to generate the id of the fields
id="formTemplate:tableForm:0:inputTextValue" ;
id="formTemplate:tableForm:1:inputTextValue" ;
id="formTemplate:tableForm:2:inputTextValue"
But when i use any of these ids in reRender attribute, the Ajax's log returns me this message:
18:23:57,208 WARN [AjaxContext] Target component for id formTemplate:tableForm:0:inputTextValue not found
I tried this but i got the same error message: reRender="#{rich:clientId('inputTextValue')}"
The weirdest thing here is that it shows me this message of the input not found, but in the html source code the id of he inputText is the same that i've puted to reRender.
Does anybody here have already delt with this problem? Any suggestions to me?
Thank you!

you should bind the h:dataTable to a variable in your bean, in order to reach the current row index.
<h:dataTable binding="#{myManagedBean.dataTable}" ...>
then you can change a4j:support like this:
<a4j:support reRender="formTemplate:tableForm:#{myManagedBean.dataTable.rowIndex}:inputTextValue" ... />

Related

Primefaces datatable filter : set a filter from the xhtml page

I d like to create several xhtml pages using the same datatable with different filter.
For example there would be a men.xhtml and women.xhtml page from and service call getHumans;
I would like the filter to be automatically applied without typing it and I dont want to create an extra view as it seems to me a lot of stuff for nothing.
I've tried these code with no success
<p:column filterBy="human.gender" filteredValue="men"
headerText="Gender" style="width: 150px;">
<h:outputText value="#{human.gender}" />
</p:column>
I've also tried to add this:
<p:dataTable id="gender" var="gender" filterValue="men" ...
but it didn't work
Any idea of what I can do?
Via the data table's filterValue attribute you should provide a list to keep the filtered data if filtering is enabled. You could restrict the list you get from your bean in xhtml using expression language (el) with a stream:
<p:dataTable value="#{yourBean.humans.stream().filter(human -> human.getGender().equals('men')).toList()}" ...>
You need EL version 3.0 or higher for this to work.

Containing div for JSF composite components

I have a number of composite components in my application, and from time to time, I need to reference those components as a whole. By default, composite components don't generate any additional mark up over their child components, so if you give a composite component an id attribute, it simply appends that id to the generated ids of the child components. I would like to reference the whole component by id (i.e. for use in jquery manipulation). JSF components do not allow EL in the id attribute, so to accomplish this, I have so far been wrapping my composite components in plain html divs as follows:
<ui:component ...
xmlns:cc="http://java.sun.com/jsf/composite"
...>
<cc:interface componentType="myComponent">
<cc:attribute name="process" type="java.lang.String" required="false" default="#form"/>
<cc:attribute name="update" type="java.lang.String" required="false" default="#form"/>
...
</cc:interface>
<cc:implementation>
<h:outputStylesheet name="myComponent.css" library="css/components" target="head"/>
<div id="#{cc.clientId}" class="myComponent #{cc.attrs.styleClass}">
... composite component implementation here ...
<p:dataTable id="note-history" styleClass="entity-notes-history" value="#{cc.notes}" var="note" paginator="true" paginatorAlwaysVisible="false"
paginatorPosition="bottom" rows="5" rendered="#{not empty cc.notes}" rowStyleClass="#{note.noteBaseType.word}">
...
<p:column rendered="#{note.noteBaseType == 'Warning' and not cc.attrs.displayOnly}" style="width: 8em;">
<p:commandButton actionListener="#{cc.cancelSeverity(note.id)}" process="#{cc.attrs.process}" update="#{cc.attrs.update} update="note-history" value="Reduce Severity"/>
</p:column>
</p:dataTable>
</div>
</cc:implementation>
And the component would be used as follows:
....
<ppa:myComponent id="myId" update="myId" />
....
Unfortunately, if I have any ajax (specifically p:ajax from primefaces) calls within the composite component, when I try to have them update the composite component by ID I get a "Cannot find component with identifier" exception. Is there any way to get JSF to auto generate a valid component and container for my composite components? I would really hate to have to generate two containing divs or spans (i.e. adding an h:panelGroup around the plain html div) just to get ajax working. Alternatively, is there a way to force JSF to allow dynamic ids on components?
Edit:
In response to BallusC's answer, I've edited the example code to be more clear in how the component is built and used, since given his answer it's entirely possible I'm just doing something that isn't allowed.
when I try to have them update the composite component by ID I get a "Cannot find component with identifier" exception
It's unfortunate that you didn't show how exactly you did that, because it should work just fine, provided that you used the composite's client ID in the update which is enclosed in the composite itself:
<f:ajax render=":#{cc.clientId}" />
Or, that you just used composite's own ID in the update which is performed outside the composite inside the same naming container parent:
<f:ajax render="myId" />
Most likely you did it the wrong way. E.g. you forgot the : prefix, or you used #{cc.id} instead of #{cc.clientId}, etc. The above has as far as I know always worked in all Mojarra 2.x versions released so far.
See also:
Referring composite component ID in f:ajax render
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
Alternatively, is there a way to force JSF to allow dynamic ids on components?
You can just use EL in id attribute, provided that it's available during view build time and thus not only during view render time. See also JSTL in JSF2 Facelets... makes sense? for related background information.
Update as per your question update wherein you finally show how you tried to achieve it;
With
<ppa:myComponent id="myId" update="myId" />
and
<p:commandButton ... update="#{cc.attrs.update}" />
you're effectively ultimately doing a
<p:commandButton ... update="myId" />
which is basically looking for a component with ID myId inside the context of the composite itself! It would only have effect on e.g. a <h:outputText id="myID"> next to the <p:commandButton> inside the same <cc:implementation>.
The functional requirement is understood, but the solution is not so nice. Your closest bet is (ab)using #this and conditionally checking for that in update:
<ppa:myComponent id="myId" update="#this" />
with something like this
<p:commandButton ... update="#{cc.attrs.update == '#this' ? ':'.concat(cc.clientId) : cc.attrs.update}" />

jsf ajax bootstrap dropdown render

I'm making form with dropdowns, where user have to make first choice, than using ajax next choices appear. It works just fine. But I wanted to add bootstrap formatting for dropodwns, so I installed bootstrap-select. It work also just fine, but when ajax event renders data for next he renders it in a new dropdown, next to still empty bootstrap formated dropdown. Witch, how can you predict, isn't desired action. Here's code from jsf:
<h:selectOneMenu styleClass="bootstrap-select" id="marka" value="#{searchBean.markiID}">
<f:selectItems value="#{searchBean.listaMarek}" var="c" itemLabel="#{c.marka}"
itemValue="#{c.markaID}"/>
<f:ajax event="change" execute="marka" render="model"/>
</h:selectOneMenu>
<h:outputText value="#{msg.carModel}"></h:outputText>
<h:selectOneMenu styleClass="bootstrap-select" id="model" value="#{searchBean.modelID}">
<f:selectItems value="#{searchBean.listaModeli}" var="p" itemLabel="#{p.model}"
itemValue="#{p.modelID}"/>
<f:ajax event="change" execute="model" render="liczbaDrzwi"/>
</h:selectOneMenu>
In backingbean, when user choose smthging from first dropdown, Is generated list of items for second dropdown, and so on. And this is the result of making choice:
As you can see, ajax makes totally new dropdown, instead of filling already existing.
Thanks for any ideas:)
JSF Ajax works in this way... instead of filling the already existing dropdown... the jee server send a new HTML fragment to replace this dropdown code...
Maybe you could read this link to understand JSF lifecycle...jsf lifeclycle
Did you try using primefaces or richfaces instead of h:selectOneMenu component?
Here is a PrimeFaces example where you can see how to update one dropdown when you select a value on another dropdown... pf example

Jsf 2 - ajax event update

I am trying to update a dropdown on change of value in a previous dropdown(in another form,another xhtml file). This is the code that am using as of now :
...
<f:selectItems value="#{createbill.episodeSetting}"/>
<p:ajax event="change" update=":chargesForm:tab2:serviceSetting"></p:ajax>
...
when this value is changed, i require the same value to show up in the other dropdown,which is in a different form(chargesForm) which is in a different file. The important thing to note is that both the dropdowns have the same values.
This code is not functioning as i per the requirement I mentioned above.
Please suggest...

jsf2 f:ajax render issue in datatable

I have a datatable and for each line have a delete linkcommand, as following:
<h:dataTable value='#{glbProjectDtoList}' var='projectDto'
binding='#{projectController.projectDataTable}' styleClass='display'
id='tblProject' rowClasses='gradeA, gradeA'
columnClasses='projectTableName, projectTableProgress, projectTableAction'>
......
<h:commandLink
action="#{projectController.delete(projectDto.projectId)}">
<img class="btnDeleteProject mr5"
src="#{request.contextPath}/resources/images/icons/dark/trash.png" />
<f:ajax execute="#form"
onevent="function(data) {deleteProjectEventHandler(data);}"
render=":tblProject" />
</h:commandLink>
......
</h:dataTable>
The delete function works fine, but the whole datatable is not reRendered, is it because the action nested in data table or by some other reason?
Update :
It's not working, after remove (:), throw following exception:
javax.faces.FacesException: <f:ajax> contains an unknown id 'tblProject' - cannot locate it in the context of the component j_idt68
means without (:), the element must be in same h:form tag.
Thanks in advance.
-Cow
Remove the : in front of the id:
<f:ajax execute="#form" onevent="function(data) {deleteProjectEventHandler(data);}" render="tblProject"/>
If the id starts with a separator character (usually :) the component is searched from the root component, otherwise it is searched from the next NamingContainer.
Have a look at the javadoc for more information: UIComponent.findComponent
This is possibly happening because the id of the datatable is not found in the viewroot when component state is getting refreshed.
To find out the exact ID by which this component is present on the
viewroot, please check the page source and find out the ID by which
this datatable is rendered.
You need to use the same ID as those found in the viewSource to allow the component to be visible in viewRoot when the state is changed.
Alternatively, UIComponent.findComponent will also help and if ID you are specifying is correct it will return you the UIComponent instance else it will return null.
I have go another approach, use hiding form outside of the table. It works.
Thanks everyone ;)

Resources