primefaces 4.0 p:graphicImage firefox bug - firefox

Here is my problem with firefox using primefaces 4.0 communication version: p:graphicImage
I have a list of model, whenever I click 1 item, I would like to get 1 image respectively
In xhtml file
<p:fieldset id="modelDiagramView" style="width:100%;height:1280px">
<p:panel id="panel">
<p:graphicImage value="#{modelBean.modelImage}" style="width: 100%;" cache="false"/>
</p:panel>
</p:fieldset>
in java bean, only session scope and application scope are running well
public StreamedContent getModelImage() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
System.out.println("render_response: id=" + modelID);
// So, we're rendering the HTML. Return a stub StreamedContent so
// that it will generate right URL.
// modelImage = new DefaultStreamedContent();
if (modelID != null)
getModelImage(modelID);
} else {
System.out.println("real reander: id=" + modelID);
if (modelID != null)
getModelImage(modelID);
}
return modelImage;
}
In chrome, when I click to item in list, the p:graphicImage will render a new image, however in firefox, only the first item's image will be render, if I want to display the next clicked item, I have to refresh browser(F5). Is it primefaces bug, how can I prevent that problem? Please help me

It's just a "bug" that browsers doesn't refresh a image with ajax if the URL will not be changed. Therefore you should add a random number to the resource url as below example.
xhtml
<p:graphicImage value="#{bean.stream}" id="pic" width="200">
<f:param name="randomNumber" value="#{beanxxx.randomNumber}"/>
</p:graphicImage>
beanxxx
public String getRandomNumber() {
Random r = new Random();
int low = 10;
int high = 100;
int result = r.nextInt(high-low) + low;
return Integer.toString(result);
}

Related

JSF + Primefaces + StreamedContent + documentViewer + ajax

I'm using Primefaces 5.2 with extensions 3.1.
I have my datatable and on click on each row I'd like to display modal and in this modal use documentViewer which will display document based on parameter passed from selected row.
With this I'm invoking my modal from within datatable
<p:ajax event="rowSelect" update=":previewDataForm" oncomplete="$('.previewDataModal').modal();" immediate="true">
<f:param name="pdfFile" value="#{row.dataPath}"/>
</p:ajax>
this is my modal:
<b:modal id="previewDataModal" title="Preview" styleClass="orderPreviewModalPseudoClass">
<h:form id="previewDataForm">
<pe:documentViewer height="550" value="#{contentStreamHelperBean.pdfFromFileSystem}" />
</h:form>
</b:modal>
and this is my stream helper
#Component("contentStreamHelperBean")
#Scope("request")
public class ContentStreamHelperBean extends BaseBean {
private static final Logger log = LoggerFactory.getLogger(ContentStreamHelperBean.class);
public StreamedContent getPdfFromFileSystem() {
String pdfFile = getRequestAttribute("pdfFile");
if (getFacesContext().getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
if (StringUtils.isNotEmpty(pdfFile))
try {
return new DefaultStreamedContent(new FileInputStream(new File(pdfFile)), "application/pdf");
} catch (FileNotFoundException e) {
log.error("Unable to get pdf", e);
}
}
return new DefaultStreamedContent();
}
}
Problem is, that when onclick is invoked I can't get pdfFile param in my ContentStreamHelper so:
how to pass parameter from dataTable rowSelect to my backingBean?
is this good approach how to display PDF with documentViewer?

Primefaces how to toggle a dashboard widget/panel visibility using ajax?

I have a dashboard with a considerable number of widgets / panels which are working just fine.
I'm looking for a way to toggle the visibility of a specific one using a commandButton ction listener without having to refresh the page, i.e. via AJAX.
<p:dashboard id="board" model="#{dashboardBean.model}">
<!-- iteration code begins -->
<p:panel id="#{wdgt.code}" header="#{wdgt.title}">
<h:outputText value="One of the dozens of widgets" />
</p:panel>
<!-- iteration code ends -->
<p:panel id="staticWdgtId" header="Static Widget Initially Invisible" visible="false">
Some static content
</p:panel>
</p:dashboard>
Then in the backing bean, at some point this action needs to be fired via a commandButton or an actionListener...
public void showTheWidget() {
DashboardColumn dbc = this.model.getColumn(1);
dbc.getWidget(2); // does not get a widget object with a visibility attribute :((
// so that I could manipulate such as dbc.getWidget(2).setVisible(true);
}
Any ideas?
STATIC APPROACH
You can associate the panel with a boolean.
Panel
<p:panel id="staticWdgtId" header="Static Widget Initially Invisible"
visible="#{bean.panelShow}">
Some static content
</p:panel>
Button
<p:commandButton actionListener="#{bean.actionListener()}"
value="Button"
update=":staticWdgtId" />
Bean
public void actionListener() {
setShowPanel(true);
}
DYNAMIC APPROACH
Render all the panel with display: none
Dashboard
<p:dashboard id="board" model="#{dashboardBean.model}">
<p:panel id="#{wdgt.code}" header="#{wdgt.title}" style="display: none">
<h:outputText value="One of the dozens of widgets" />
</p:panel>
</p:dashboard>
remoteCommand
<p:remoteCommand name="panelsToShow"
actionListener="#{bean.panelsToShowAction()}"
oncomplete="handleComplete(xhr, status, args)" />
bean.panelsToShowAction() you need Gson
public void panelsToShowAction() {
List<String> panels = new ArrayList<String>();
//iterate over the panels you want to show, and put #{wdgt.code} which is the id of the panel
panels.add("Code1");//id
panels.add("Code2");//id
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("panels", new Gson().toJson(panels));
}
JS
$(document).ready(function() {
panelsToShow();
})
function handleComplete(xhr, status, args) {
var panels = eval('(' + args.panels + ')');
for (var i = 0, len = panels.length; i < len; i++) {
$('#'+panels[i]).show();
}
}

Styling UIInputs that fail validation

the problem
I'm trying to work with form validation in jsf 1.2. I have a form with rows of two input text fields.
I enter two rows of data, with one bad cell, like this:
| :) | :/ |
| :) | :) |
The validator is called once for each row, but checks both fields.
Each UIInput that fails validation is added to a list of failed UIComponents.
The method for the submit action finally gets to run.
First it restores any saved styles.
Then it loops over the failed UIComponents.
Inside the loop, it saves the current style, then sets the style to "badInput".
But when the page loads, both end-cells have the "badInput" style:
| :) | :/ |
| :) | :/ |
my code
This is my validator, a method on the managed bean that handles this page:
public void validateTime(FacesContext context, UIComponent component, Object value)
{
UIInput out = (UIInput) component.findComponent("out");
for (UIComponent uic : Arrays.asList(component, out))
{
String time = (String) ((UIInput)uic).getSubmittedValue();
if (!StringToTime.isValid(time))
{
// mark that we found invalid times
validTimes = false;
// save the failed component
// the click method will change the style during the render phase
failedUics.add(uic); // List<UIComponent>
badComps.put(uic.getClientId(context), uic); // Map<String, UIComponent>
}
}
}
And here's the table of input fields:
<h:dataTable binding="#{entryHandler.tableAttends}" value="#{entryHandler.attends}" var="range">
<h:column>
<div>
<h:outputLabel>
<h:outputText value="In: " />
<h:inputText value="#{range.start}" id="in" validator="#{entryHandler.validateTime}" />
</h:outputLabel>
<h:outputLabel>
<h:outputText value="Out: " />
<h:inputText value="#{range.end}" id="out" />
</h:outputLabel>
<h:commandLink action="#{entryHandler.delAttend}" value="X" styleClass="removeTime" />
</div>
</h:column>
</h:dataTable>
I've tried applying the bad input style these two ways:
for (UIComponent target : failedUics)
{
log.debug("target client id: " + target.getClientId(context));
Map<String, Object> attr = target.getAttributes();
// save the style before changing it
String style = (String) attr.get("styleClass");
originalStyle.put(target.getClientId(context), style);
// add the badInput css class
if (style == null) style = "";
attr.put("styleClass", "badInput " + style);
}
failedUics = new ArrayList<UIComponent>();
and the second:
UIComponent root = context.getViewRoot();
for (String clientId : badComps.keySet())
{
root.invokeOnComponent(context, clientId, new BadInputCallback(originalStyle));
}
badComps = new HashMap<String, UIComponent>();
where this is the callback function:
private static class BadInputCallback implements ContextCallback
{
private final Map<String, String> originalStyle;
public BadInputCallback(Map<String, String> originalStyle)
{
this.originalStyle = originalStyle;
}
#Override
public void invokeContextCallback(FacesContext context, UIComponent target)
{
Map<String, Object> attr = uic.getAttributes();
// save the style before changing it
String style = (String) attr.get("styleClass");
originalStyle.put(target.getClientId(context), style);
// add the badInput css class
if (style == null) style = "";
attr.put("styleClass", "badInput " + style);
}
}
Your concrete problem is caused because there is physically only one input component in the component tree, whose state changes whenever the parent UIData component iterates over every item of the model. When you want to set the styleClass dynamically, you basically need to let it depend on the currently iterated item, like so:
<h:dataTable ... var="item">
<h:column>
<h:inputText ... styleClass="#{item.bad ? 'badInput' : ''}" />
</h:column>
</h:dataTable>
Or when you're already on JSF 2.x, then check UIInput#isValid() instead whereby the UIInput is referenced via implicit EL variable #{component}, like so:
<h:dataTable ... var="item">
<h:column>
<h:inputText ... styleClass="#{component.valid ? '' : 'badInput'}" />
</h:column>
</h:dataTable>
This problem is already identified before and taken into account in among others the JSF 1.2 targeted SetFocusListener phase listener on The BalusC Code and the JSF 2.0 <o:highlight> component of JSF utility library OmniFaces.
Both have under the covers the same approach: they collect the client IDs of all invalidated input components and pass them as an array to JavaScript code which in turn sets the desired class name via HTML DOM.
See also:
What exactly is #{component} in EL?
how to set ui-state-error class to h:selectOneMenu on validation error
Styling input component after validation failed
Eclipse errors on #{component.valid}: "valid cannot be resolved as a member of component”

JSF Ajax addClientBehavior gives null.pointer.exception

I'm trying to add programatically an Ajax client behavior to a custom component but when I do I get a null.pointer.exception (as an Alert in the browser no error in the logs), if I add the behavior in the .xhtml it works fine but I really need to add them programatically (actually the component is going to be rendered dinamically from a top component (dashboard -> N columns -> N widgets per column all from a Database)
I have tested this creating a simple DataList component
Here is the relevant code...
DataListRenderer
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException{
DataList datalist = (DataList)component;
ResponseWriter writer = context.getResponseWriter();
.. bunch of rendering options....
// If sortable then we add the sortable script.
// This basically ends up generating a call to jsf.ajax.request(source,event,params);
if (sortable != null && sortable.equalsIgnoreCase("true")) {
ScriptUtils.startScript(writer, clientId);
writer.write("$(function() {");
writer.write("$(EasyFaces.escapeId('" + clientId + "')).sortable({");
writer.write("update: function (event, ui) { ");
writer.write(new AjaxRequest().addEvent(StringUtils.addSingleQuotes("update"))
.addExecute(StringUtils.addSingleQuotes(datalist.getClientId()))
.addSource(StringUtils.addSingleQuotes(datalist.getClientId()))
.addOther("sourceId", "ui.item.attr('id')")
.addOther("dataValue", "ui.item.attr('data-value')")
.addOther("dropedPosition", "ui.item.index()")
.getAjaxCall());
writer.write(" } ");
encodeClientBehaviors(context, datalist);
writer.write("});");
writer.write("});");
ScriptUtils.endScript(writer);
}
// This is where I add the behavior
AjaxBehavior ajaxBehavior = (AjaxBehavior) FacesContext.getCurrentInstance().getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
ajaxBehavior.setRender(Arrays.asList("#form"));
ajaxBehavior.setExecute(Arrays.asList("#form"));
MethodExpression listener = FacesContext.getCurrentInstance().getApplication()
.getExpressionFactory().createMethodExpression(context.getELContext(),"#{dataListManager.updateModel}", null,
new Class[] { AjaxBehaviorEvent.class });
ajaxBehavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl(listener));
datalist.addClientBehavior(datalist.getDefaultEventName(), ajaxBehavior);
}
... rest of the code
Now the .xhtml is as follows:
...
h:form>
<et:dataList id="dl" value="#{easyfacesBean.data}" itemValue="foo" var="xx" sortable="true">
<h:outputText id="txt" value="#{xx}" />
</et:dataList>
</h:form>
...
This renders the code Ok, the list actually can be ordered but when re-ordered it gives me the null.pointer.exception error
This is what comes back from the server:
<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class java.lang.NullPointerException</error-name><error-message><![CDATA[]]></error-message></error></partial-response>
Now, If I comment this line
datalist.addClientBehavior(datalist.getDefaultEventName(), ajaxBehavior);
And simply add the tag like so:
<h:form>
<et:dataList id="dl" value="#{easyfacesBean.data}" itemValue="foo" var="xx" sortable="true">
<f:ajax />
<h:outputText id="txt" value="#{xx}" />
</et:dataList>
</h:form>
Everything works fine.. any ideas? I would settle for a way to actually know where the null.point.exception is ..
BTW if I don't comment the line that actually add's the behavior and add the < f:ajax > tag the error changes to java.lang.IndexOutOfBoundsException
<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class java.lang.IndexOutOfBoundsException</error-name><error-message><![CDATA[Index: 1, Size: 1]]></error-message>
Regards!

How to use p:graphicImage with StreamedContent within p:dataTable? [duplicate]

This question already has answers here:
Display dynamic image from database or remote source with p:graphicImage and StreamedContent
(4 answers)
Closed 7 years ago.
I want to dynamically load images from a database withing a PrimeFaces data table. Code looks like as follows which is based on this PF forum topic:
<p:dataTable id="tablaInventario" var="inv" value="#{registrarPedidoController.inventarioList}" paginator="true" rows="10"
selection="#{registrarPedidoController.inventarioSelected}" selectionMode="single"
update="tablaInventario tablaDetalle total totalDesc" dblClickSelect="false" paginatorPosition="bottom">
<p:column sortBy="producto.codigo" filterBy="producto.codigo">
<f:facet name="header">#{msg.codigo}</f:facet>
#{inv.producto.codProducto}
</p:column>
<p:column>
<f:facet name="header">Foto</f:facet>
<p:graphicImage id="photo" value="#{registrarPedidoController.streamedImageById}" cache="FALSE">
<f:param name="inv" value="#{inv.id}" />
</p:graphicImage>
</p:column>
</p:dataTable>
with
public StreamedContent getStreamedImageById() {
DefaultStreamedContent image = null;
String get = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("inv");
System.out.println("[Param]: " + get); // This prints null.
Long id = new Long(get);
List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();
for (Inventario i : listInventarios) {
if (i.getId().compareTo(id) == 0) {
byte[] foto = i.getProducto().getFoto();
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
}
}
return image;
}
However I can't get it work. My param is passing "null" to my backing bean. How is this caused and how can I solve it?
I am using Netbeans 6.9.1, JSF 2.0 and Primefaces 2.2.RC2.
I went on using BalusC first solution, it worked fine but images aren't being rendered in the UI. Exceptions Glassfish is throwing up:
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at com.sun.faces.mgbean.BeanManager$ScopeManager$ViewScopeHandler.isInScope(BeanManager.java:552)
Well seems I get working thanks to BalusC. I've to used RequestScoped, SessionScoped or ApplicationScoped for managing the getStreamedImageId. However in the UI is always setting the default image (for the null cases) and not as expected the image that correspondes to each row. The new code is:
public StreamedContent streamedById(Long id) {
DefaultStreamedContent image = null;
System.out.println("[ID inventario]: " + id);
List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();
for (Inventario i : listInventarios) {
if (i.getId().equals(id)) {
byte[] foto = i.getProducto().getFoto();
if (foto != null) {
System.out.println(" [Foto]: " + foto);
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
break;
}
}
}
if (image == null) {
System.out.println(" [Image null]");
byte[] foto = listInventarios.get(0).getProducto().getFoto();
image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
}
System.out.println(" [Foto Streamed]: " + image);
return image;
}
The <p:graphicImage> will call the getter method twice. First time is when the <img> element is to be rendered to HTML and thus requires an URL in the src attribute. If you just return new DefaultStreamedContent(), then it will autogenerate the right URL in src attribute. Second time is when the browser really requests the image, this is the moment when you should return the actual image.
So, the getter method should basically look like this:
public StreamedContent getStreamedImageById() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Get ID value from actual request param.
String id = context.getExternalContext().getRequestParameterMap().get("id");
Image image = service.find(Long.valueOf(id));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
}
}
images are saved in the database as byte[] if we save them through hibernate. I uploaded the images with <p:fileUpload... tag then I save the image alongwith other data values using hibernate.
On second page, I'm displaying the whole table data (of course with images) using
<p:dataTable var="data" value="#{three.all}" ....
and dynamic Images using
<p:graphicImage alt="image" value="#{three.getImage(data)}" cache="false" >
<f:param id="image_id" name="image_id" value="#{data.number}" />
</p:graphicImage></p:dataTable>
Here "three" is the name of Backing Bean. In method getAll(), I'm retrieving data from table through hibernate and in the same method, I've created a HashMap<Integer, byte[]>. HashMap is an instance variable of the bean and The Bean is SessionScoped. I'm putting the images (which are in byte[] form) alongwith an integer image_id.
code:
for (int i=0; i<utlst.size(); i++ ){
images.put(utlst.get(i).getNumber(), utlst.get(i).getImage());}
//utlst is the object retrieved from database. number is user-id.
In the view getImage.xhtml, <p:graphicImage alt="image" value="#{three.getImage(data)}" cache="false" > it calls the method getImage(data /*I am passing current object of the list which is being iterated by*/ )
code of getImage:
public StreamedContent getImage(Util ut) throws IOException {
//Util is the pojo
String image_id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("image_id");
System.out.println("image_id: " + image_id);
if (image_id == null) {
defaultImage=new DefaultStreamedContent(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/Capture.PNG"), "image/png");
return defaultImage;
}
image= new DefaultStreamedContent(new ByteArrayInputStream(images.get(Integer.valueOf(image_id))), "image/png");
return image;
}
just keep your dynamic Images with ids in A HashMap in the session then they will be correctly streamed.
Thanks & regards,
Zeeshan
In PrimeFaces 3.2 the bug is still present. I do the workaround with
<p:graphicImage value="#{company.charting}">
<f:param id="a" name="a" value="#{cc.attrs.a}" />
<f:param id="b" name="b" value="#{cc.attrs.b}" />
</p:graphicImage>
and
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String a= externalContext.getRequestParameterMap().get("a");
String b= externalContext.getRequestParameterMap().get("b");
But even with this the bean is called 2 times. But in the second call variable a + b is filled ;-)
Damn bug

Resources