Displaying the same image several times with multiple p:graphicImage without multiple HTTP requests - image

I'm using p:graphicImage tag in my XHTML page to displaying the same image in small an large :
<f:facet name="header">#{msgs.ATTR_PICTURE}</f:facet>
<h:panelGroup>
<p:graphicImage id="product_thumbnail" styleClass="thumbnail"
cache="false" value="#{imageBean.streamedImageById}">
<f:param name="productId" value="#{_product.id}" />
</p:graphicImage>
<p:tooltip id="imagebigger" for="product_thumbnail" position="right" showDelay="0" showEffect="blind" styleClass="tooltip_thumbnail">
<p:graphicImage value="#{imageBean.streamedImageById}" styleClass="thumbnail_large" cache="false">
<f:param name="productId" value="#{_product.id}" />
</p:graphicImage>
</p:tooltip>
</h:panelGroup>
I would like to avoid the 2 HTML requests systematically for each image to display. Is there a way to avoid that ?

You could use the stream attribute and set it to false.
This will render the image in base64 instead of rendering the URL to the image.
I don't suggest it as the markup will be very big and probably much worse performance.

I you remove the cache="false" from the first p:graphicImage (it defaults to true) the image is retrieved in the first <img ... /> (which the p:graphicImage renders to) on the client and just displayed from the client cache for the second one without retrieving it twice.
The cache="false" might have been there for a reason like you mentioned in the comments, but that is effectively a new question for which there are several Q/A in Stackoverflow but which one is the most appropriate depends on the details of your use case. Your new question might either be a duplicate again or a new valid question on its own... It might even be that returning the cache="true on the first p:graphicImage and replacing the second one with something else (even some pure client-side 'duplication' e.g.) might be a good approach.

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

What is the client-side behavior of a JSF WebSocket when it is removed from the DOM

I have several panels, each displaying some contents, and zero, one, or more of these panels can be displayed, as in the following example:
<div jsf:id="contents">
<ui:fragment rendered="#{aContent.rendered}">
<h:form>
<o:socket channel="a-channel" onmessage"onAMessage"/>
<o:commandScript name="onAMessage"
actionListener=#{aContent.update()}"
render=":aComponent"/>
</h:form>
<my:aComponent id="aComponent" />
</ui:fragment>
<ui:fragment rendered="#{bContent.rendered}">
<h:form>
<o:socket channel="b-channel" onmessage"onBMessage"/>
<o:commandScript name="onBMessage"
actionListener=#{bContent.update()}"
render=":bComponent"/>
</h:form>
<my:bComponent id="bComponent" />
</ui:fragment>
</div>
I would like to know what happens to the client side web socket when one of these UI fragments is removed from the DOM after an AJAX update of the enclosing element.
Is the web socket closed?
Should I consider another approach?
Based on how it's currently implemented, it'll keep running. You need to repeat the condition in the connected attribute.
<ui:fragment rendered="#{aContent.rendered}">
<o:socket ... connected="#{aContent.rendered}" />
Perhaps this will be improved later when I plan to add <f:ajax> support for <o:socket>.
On the other hand, your code snippet is non-DRY. Try restricting to only 1 socket+commandScript combination which does its job dynamically based on contents of the pushed message. See also Channel design hints section of the documentation.

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

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.

Get the selected values from a rich:select which is inside o a4j:repeat

I am using a a4j:repeat control to iterate throughtout a Map<Object, List<MyType>> list. The XHTML page displays both h:outputText and rich:select controls.
I loop throughout a Map<String, List<Items>> instance, to show a master-detail tables. In the h:outputText I show the master description and the rich:select shows the detail.
The code is as follows:
customer.xhtml
<a4j:repeat value="#{masterManagedBean.listMasterItems.entrySet().toArray()}"
var="itemsVar">
<h:outputText value="#{itemsVar.key}" />
<rich:select enableManualInput="true">
<f:selectItems value="#{itemsVar.value}" id="itemsMenu"
var="itemsVarSelect"
itemLabel="#{itemsVarSelect.descriptionItems}"
itemValue="#{itemsVarSelect.idItems}" />
</rich:select>
</a4j:repeat>
This snippet works perfect. But, I don't have any idea how to gain the selected value from every rich:select generated by the repeater. Please guidance me to solve this issue.
Basically I would suggest not to use the datastructure Map<String,List> for the described case. Why not changing the Structure into a normal List of objects (List<SelectionObject>) with the SelectionObject-class holding:
name/label
possible values (as List or Array)
selected value
So the JSF code would look something like
<a4j:repeat value="#{masterManagedBean.listMasterItems}"
var="itemsVar">
<h:outputText value="#{itemsVar.label}" />
<rich:select enableManualInput="true" value="#{itemsVar.selectedValue}">
<f:selectItems value="#{itemsVar.possibleValues}" id="itemsMenu"
var="itemsVarSelect"
itemLabel="#{itemsVarSelect.descriptionItems}"
itemValue="#{itemsVarSelect.idItems}" />
</rich:select>
</a4j:repeat>
Any preparations/building for this object structure can be done e.g. in getListMasterItems (use some caching), the retrieval of the users data is done in the action of your submit-button, anyway. Just iterate through the list and read out the `selectedValue. If the answer is usable/helpful, please consider an upvote, confirm if it worked out for you.
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.

Resources