Ajax rendering "freezes" for a while when updating h:selectManyListbox with 10.000 items - ajax

I am using Mojarra JSF (v2.2.10) with Spring (v3.2.5) for a small admin-console on a tomcat (also Twitter Bootstrap for styling).
Basically there is a multiple select box which I can add new entries to via textbox and button. I can also remove entries by selecting them and clicking the remove button.
Here is the relevant code piece:
<h:form>
<h:outputLabel for="selectedEntries" value="Selected entries" />
<h:selectManyListbox id="selectedEntries" value="#{myBean.entriesToRemove}">
<f:ajax/>
<f:selectItems value="#{myBean.selectedEntries}" />
</h:selectManyListbox>
<h:commandButton action="#{myBean.addEntriesToSelection}" value="Add">
<f:ajax render="selectedEntries entriesInput" />
</h:commandButton>
<h:commandButton action="#{myBean.removeEntriesFromSelection}">
<f:ajax render="selectedEntries entriesInput" />
</h:commandButton>
<h:outputLabel for="entriesInput" value="Input" />
<h:inputTextarea id="entriesInput" value="#{myBean.entriesInput}">
<f:ajax/>
</h:inputTextarea>
The fields "entriesToRemove" and "selectedEntries" are simple String Lists and the field "entriesInput" is a String.
Everything works just fine, but when the "selectedEntries" list grows to say 10.000 entries, I hit a performance problem: When I try to add a new entry into this overgrown list, the page freezes for about 30 seconds before it renders the updated list. The same goes for removing an entry. This freeze however does not occur in the method "addEntriesToSelection" but rather afterwards, when the backing bean fields are already updated. So I assume this has something to do with the rendering of the page.
Does anybody have a clue, how I could solve this problem? Is this maybe Mojarra- or JSF-specific?

This is a client side problem, not a server side problem. Some browsers, particularly MS Internet Explorer, are known to be laggy when updating the HTML DOM tree with an "insane" amount of new HTML elements. Certainly 10.000 listbox items is "insane". Google e.g. also doesn't show all those million potential matches at once when you open the search homepage. Instead, it shows an autocomplete-capable input field allowing you to find and filter the relevant data.
Consider turning that listbox into a search/autocomplete input field.

Related

JSF cannot update single form in ui:repeat from outside

I have two problems which are closely related:
I need to update a form inside a tag inside ui:repeat from a dialog at the main page and cannot figure out how (because there are many tags in the ui:repeat and I need to update only one)
naming containers are messed up and lose their "index" when I use id in that form (in case of trying to determine the update path expression...)
reason I need this: updating the 'wholelist' (current situation) breaks all <p:calendar> inside the <p:dialog> somehow (no errors...) (the calendar overlay shows at the first time, but after updating the list it does not appear any more (must reload page again). Also I don't want to update 100 elements each time if only one can be changed
page.xhtml
<h:panelGroup id="wholelist">
<ui:repeat var="entry" value="#{bean.foundEntries}" id="repeatId">
<customTag:someTag entry="#{entry}" />
</ui:repeat>
</h:panelGroup>
...
<p:dialog widgetVar="dialog" id="dialog">
<p:calendar value="#{bean.date}" ... /> <!-- overlay pops up on select until the whole list is refreshed. after that it does not appear until page reload -->
<p:commandButton actionlistener="#{bean.saveSomething()}" update="#{bean.componentToUpdate WHICH DOES NOT WORK...}"/>
</p:dialog>
someTag.xhtml
and within the <customTag:someTag> (which is a tag because of multiple reuses) :
...
<h:form>
... display a lot of data which can be changed by the dialog...
<p:commandButton value="show edit dialog" onComplete="PF('dialog').show()" update=":dialog">
<f:setPropertyActionListener value="??? (#form does not work)" target="#{bean.componentToUpdate}" />
</p:commandButton>
</h:form>
First Question:
I need to refresh one single form from the dialog (=the dialog which needs to know which form I want to refresh, and I have no idea how to do so...)
And how can I get the update-logic working (pass the component to update to the bean so the dialog knows what to update or equal)?
Second Question:
why does JSF generate in case of not defining a id="..." to a naming container within a ui:repeat something like
repeatId:0:j_id_c0_6
repeatId:1:j_id_c0_6
repeatId:2:j_id_c0_6
and when I define a id to the form (<h:form id="formname">) something like
repeatId:formname
repeatId:formname
repeatId:formname
which causes duplicateId (because the lack of the "iterator-number" in the name)?
Does this make sense?
I have solved it; error was elsewhere: I have forgotten in an included tag file which caused the js warning (which broke the calendar).
many thanks

<f:ajax> executing different forms

So I have 2 forms and a command button with f:ajax attached on it. I want to execute the second form on click on button but it seems that it ignores when I'm passing the form's id on execute attribute. But when I replace it with 'execute=":form1"' it runs correctly(the information from the form is sent to server). Can someone tell me why won't work with the id of second form, or how can I achieve this: with one button to execute any form i want from the page.( as it is now no information is sent to server, only the listener is called).
Code bellow:
<h:form id="form1">
<h:panelGrid id="inputSection" >
<h:inputText id="input1" value="#{counterMB.number1}" />
<h:inputText id="input2" value="#{counterMB.number2}" />
</h:panelGrid>
<h:outputLabel id="sumResponse2" value="#{counterMB.sum}" />
</h:form>
<h:form id="form2">
<h:panelGrid id="inputSection" >
<h:inputText id="input1" value="#{counterMB.number1}" />
<h:inputText id="input2" value="#{counterMB.number2}" />
</h:panelGrid>
<h:outputLabel id="sumResponse2" value="#{counterMB.sum}" />
</h:form>
<h:commandButton value="Sum numbers">
<f:ajax event="click" execute=":form2" listener="#{counterMB.sum}" render=":form2 :form1"/>
</h:commandButton>
Update:
so to be more explicit: from what I have read I can use ajax to update/refresh etc some parts of a page instead of refreshing the whole page. What i have tried to do is group some components in different forms and execute a form at a time to see how it behaves. It works perfectly if I use the id of first group(form) but doesn't work at all if I use the id of the second form(it calls the action but doesn't submit any data from any form). I don't understand why. (PS for those who claim i lack some knowledge : this is the reason of asking questions isn't it? I'm trying to learn some new stuff)
It seems that you are lacking basic knowledge of how jsf works. A command button must be inside a form. And it's not possible to submit 2 forms with one single button.
The attribute execute of f:ajax tells which components to process, for example if you have 2 input texts, you can process only one and ignore the other using this attribute. but it's not possible to do what you are trying to do.
It doesn't really make sense to submit 2 forms and execute a single action method once.. there's no point in having 2 forms. why don't you put everything inside a single form?
In your current solution, you use a h:commandButton outside of any h:form - this is a little bit against HTML and JSF, so don't count on it. What I would suggest is
if you use Richfaces, put a a4f:jsFunction in every form and trigger the resulting Javascript from anywhere
if you use Primefaces, put a p:remoteCommand in every form and trigger the resulting javascript from anywhere
if you neither use any of them, put a <h:commandButton /> in every form, set the style hidden and use javascript to submit the form.
Hope it helps...

Richfaces dataTable works fine, but ExtendedDataTable is not showing data

We are using Richfaces 4.1.0, and I am trying to use an extendedDataTable. I started (for simplicity's sake) with dataTable. The code below works fine, and shows my data in a table, as expected.
<rich:dataTable value="#{recipientBean.recipientList}" var="recipient" selectionMode="none" id="recipientTable">
<rich:column sortable="false" id="col_1" label="Name">
<f:facet name="header">
<h:outputText value="Name" id="name" />
</f:facet>
<h:outputText value="#{recipient.name}" id="rec_name" />
</rich:column>
<!-- More columns below, removed for post brevity -->
</rich:dataTable>
We are expecting a large number of records, so we would like the table to be scrollable. I thought that I could just change the dataTable to extendedDataTable, however, when I do that, no data shows up at all.
I just started to inspect the element in Chrome, and all of a sudden the data showed up. So when I inspect the element, I see the values in the html, but they don't display when the page loads.
Could this be a style issue? An attribute that is missing (something that is needed for extendedDataTable, but not needed for dataTable)?
What else am I missing?
EDIT: I do have this extendedDataTable inside a rich:tabPanel. When I remove the rich:tabPanel it displays correctly (but I really need the tabPanel). Is this a known issue?
EDIT2: It does display correctly if it is on the first tab of the rich:tabPanel.
I found a bug report on the joss site. The work around was to use the switch type of Ajax instead of client for the tab panel.
If it still doesn't work after switching to ajax switchType you may try to use redirect instead of forward, when you navigate to the page with rich:extendedDataTable. To achieve this you may e.g. add ?redirect-faces=true to the page URL.

JSF 2.0 - Ajax and Rendered Components

I'm experiencing some problems when using the "rendered" attribute with ajax behavior. I'll paste the code so I think it will be a lot more clear:
<h:selectOneMenu value="#{registrarVentaController.esCobroChequeString}">
<f:selectItem itemLabel="Efectivo" itemValue="false"/>
<f:selectItem itemLabel="Cheque" itemValue="true"/>
<f:ajax execute="#this" render="#form"/>
</h:selectOneMenu>
<h:panelGroup id="panelMonto">
<span>Monto:</span>
<h:inputText value="#{registrarVentaController.monto}" rendered="#{registrarVentaController.banCobroCheque}"/>
<h:inputText value="#{registrarVentaController.monto}" rendered="#{not registrarVentaController.banCobroCheque}"/>
</h:panelGroup>
My "#{registrarVentaController}" is just a View Scoped JSF Managed Bean with appropiate setters/getters.
This way it works, I mean, when user selects option "Efectivo", panelGroup "panelMonto" will get updated and we'll see the first inputText, and conversely when user selects option "Cheque" user will see the second inputText.
For this approach I used "f:ajax" component where I updated the whole #form to get this behavior work and I just want to update panelGroup "panelMonto" (using render="panelMonto" It doesn't work at all (I even try with full scope resolution :formName:panelMonto with no result).
I just want to have rendered work with ajax="idComponent" or similar behavior to show certain parts according what user have selected.
Best Regards!
Note (One solution)
I managed to get a solution (taking as an input
JSF rendered is not working
and a bit of myself). I've just moved to a new form the part that I'm
interested in filtering according what user selected. This way I still
use #form ajax's render and it will just render this new form (not the
whole form as I was using!) Neverthless I'm still wondering if there
is a solution to not used #form and just the component/s ID.
what if you check with
render=":panelMonto"
not
render=":formName:panelMonto"
still not working?
this should work only with
render="panelMonto" //because is in the same form
Can you add more code?
Also can you check with your browser (in chrome: right click, inspect element, network) to see if there is any activity?? perhaps is rendering the same thing because of you...

p:commandButton update doesn't work in ui:include

I want to update a part of a page by PPR.
This is the part of page that i want to update:
<h:panelGroup id="aggiungiAuto"
rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
While this is the commandButton present in aggiungi_auto.xhtml
<p:commandButton value="Submit"
update="growl aggiungiAuto aggiungiFoto"
actionListener="#{autoBean.insert}"/>
Any Idea?
JS/Ajax works on the client side, not on the server side. JSF works on the server side, not on the client side. When you instruct JSF to not render the component to HTML, then nothing will be present in the client side, so JS/Ajax will be unable to locate the HTML element to refresh/update.
You need to wrap it in another <h:panelGroup>.
<h:panelGroup id="aggiungiAuto">
<h:panelGroup rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
</h:panelGroup>
This way the <span id="aggiuniAuto"> is always present in the client side, so JS/Ajax will be able to update it with the new HTML data generated by JSF.
So I was having this kind of a problem with PrimeFaces (the above answer not being sufficient this time), and I also discovered a solution.
Part of the problem I think was that I was using ui:include recursively. For whatever reason, PrimeFaces was irrationally causing UI components to be bound to the backend data out-of-sync; e.g., when an "Add" button was clicked, a new value would be created in the UI, but then the data for it would be ripped out of the values for the section below, etc...
The explanation? "[O]n a viewscoped bean, a hidden field is added to the form to hold post-back data[;] if that field is not included with the process, then the bean will lose context." This particular problem is prevalent with ui:include recursion especially. Solution (all regarding the p:commandButton or other actionable component):
Ensure that update and process are pointing to a JSF component, not a regular HTML component.
update the next scope up if it breaks (goes out-of-sync with the binding).
Use styleClass's for update (not e.g. PF ID's or #this:#parent kind of stuff), so that jQuery is utilized instead of PF, e.g.: #(.fieldset-class).
process whatever scope is being updated. (This is needed for the post-back data so that the Bean keeps its context for the update...) process="#this" is not needed here, provided that the button is contained by the process value component.
For all buttons without validation wanted, set immediate="true".
If none of the above works (which happened with the Add buttons, probably due to ui:include recursion), set process="#this", immediate="true", and update="#none", and then oncomplete="remoteCommandName();", and have a p:remoteCommand instead with that name with the process, immediate, and update mentioned in the above points.
If none of the above works (which happened with some other buttons, probably due to being yet another layer deeper in the ui:include recursion)... wrap a h:panelGroup around the next c:forEach up and then update the PrimeFaces ID of that in the button itself while keeping its remoteCommand call afterwards, as specified above.
If none of the above works (which happened yet again to me)... Try the following code:
In the p:commandButton(s): oncomplete="$('.FixButtonSC').click();"
In the p:fieldset with a style class of FieldsetSC:
<!-- Fix (hidden) button. -->
<p:commandButton id="FixButton" styleClass="FixButtonSC"
process="#this" update="#(.FieldsetSC)" style="display: none;" />
Hope that helps...

Resources