Display a p:overlayPanel at a specific position relative to another component (p:graphicImage) - jsf

Using a <p:overlayPanel> to display a <p:fileUpload>, when a <p:graphicImage> is clicked as follows.
<p:graphicImage id="image"
library="default"
name="test/Sunset.jpg"
style="left: 400px; top: 100px; position: relative;"
height="200"
width="200"/>
<p:overlayPanel for="image" my="top left" at="bottom right"
dynamic="true" showCloseIcon="true" dismissable="true">
<p:fileUpload mode="advanced"
fileLimit="1"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
fileUploadListener="#{bean.listener}"/>
</p:overlayPanel>
When the given <p:graphicImage> is clicked, a <p:fileUpload> is displayed in a <p:overlayPanel> as can be seen in the following picture.
I however, need to display this <p:overlayPanel> (holding a <p:fileUpload>) in a way that the bottom right corner of this <p:overlayPanel> positions over the top left corner of the given <p:graphicImage> (just because this unnecessarily introduces an ugly horizontal scroll bar on the browser where this is actually implemented (inside a <p:dataTable>)).
These attributes my="top left" at="bottom right" are expected to do the trick but they do not.
Is this achievable anyway?
According to the answer, <p:fileUpload> looks like the following, when a file is uploaded.
Which stays away from removing the horizontal scroll bar in the browser.

One way to do it is to dynamically resize the <p:overlayPanel> with an onshow event to match the <p:graphicImage> dimensions.
Here's an example :
<h:form id="form">
<p:graphicImage id="img" value="/res/img/img.jpg" />
<p:overlayPanel id="overlay" for="img" my="right bottom" at="left bottom" onShow="resize();" >
<p:fileUpload />
</p:overlayPanel>
<script type="text/javascript">
function resize() {
$("[id='form2:overlay']").css("left", "auto");
$("[id='form2:overlay']").css("right", $("[id='form2:img']").css("width"));
}
</script>
</h:form>
EDIT :
Fixed code to work inside a form.
EDIT 2:
Changed code to dynamically position overlay's right side on img's left side.
Since the img in in the last table column on the right, we can just substract img's width from right absolute position.

Related

How do you wait for an image to load before displaying a p:dialog?

I have a page in my application that uses a PrimeFaces DataTable to display a list of people with a small image of each person in the first column. When the user clicks on the small image which is part of a p:commandLink, I use ajax to update a p:graphicImage in a p:dialog with the path to the selected image and use the commandLink's oncomplete to display the dialog. Finally, I use the dialog's onShow to center the dialog on the page. The following is the xhtml:
.
.
.
<p:commandLink
update="portrait"
oncomplete="PF('portrait-dialog').show());">
<f:setPropertyActionListener
value="#{portrait}"
target="#{portraits.portrait}" />
<p:graphicImage
value="/files#{portrait.path}"
style="height: 192px; width: auto;" />
</p:commandLink>
.
.
.
<p:dialog
id="portrait-dialog"
showHeader="false"
widgetVar="portrait-dialog"
modal="true"
responsive="true"
onShow="positionDialog('portrait-dialog')">
<p:graphicImage
id="portrait"
style="max-height: 85vh;"
value="/files#{portraits.portrait.path}"
onclick="PF('portrait-dialog').hide();" />
</p:dialog>
The above code works perfectly but uses a single image file for the small image in the list and the big image in the dialog. I decided to use different image files for the small and big image so created the following code.
.
.
.
<p:commandLink
update="portrait"
oncomplete="PF('portrait-dialog').show();">
<f:setPropertyActionListener
value="#{portrait}"
target="#{portraits.portrait}" />
<p:graphicImage
value="/files#{portrait.getPath('_162x288.jpg')}"
style="height: 192px; width: auto;" />
</p:commandLink>
.
.
.
<p:dialog
id="portrait-dialog"
showHeader="false"
widgetVar="portrait-dialog"
modal="true"
responsive="true"
onShow="positionDialog('portrait-dialog')">
<p:graphicImage
id="portrait"
style="max-height: 85vh;"
value="/files#{portraits.portrait.getPath('_810x1440.jpg')}"
onclick="PF('portrait-dialog').hide();" />
</p:dialog>
Unfortunately, the above code does not center the dialog on the page correctly the first time the user selects the small image. If the user closes the dialog and then selects the small image again, the dialog is centered correctly on the page. I suspected that this had something to do with the large image not being downloaded completely before the dialog was diplayed so I add a 50ms delay to the oncomplete as shown below.
<p:commandLink
update="portrait"
oncomplete="setTimeout(function(){PF('portrait-dialog').show();}, 50);">
<f:setPropertyActionListener
value="#{portrait}"
target="#{portraits.portrait}" />
<p:graphicImage
value="/files#{portrait.getPath('_162x288.jpg')}"
style="height: 192px; width: auto;" />
</p:commandLink>
This resolved the issue in most cases but sometimes the dialog is still not centered correctly on the first selection.
How do I wait for an image to load before displaying a p:dialog?
I resolved this issue by moving the dialog show from the commandLink's oncomplete to an onload passthrough attribute of the dialog's imageGraphic as shown below.
.
.
.
<p:commandLink
update="portrait"
oncomplete="">
<f:setPropertyActionListener
value="#{portrait}"
target="#{portraits.portrait}" />
<p:graphicImage
value="/files#{portrait.getPath('_162x288.jpg')}"
style="height: 192px; width: auto;" />
</p:commandLink>
.
.
.
<p:dialog
id="portrait-dialog"
showHeader="false"
widgetVar="portrait-dialog"
modal="true"
responsive="true"
onShow="positionDialog('portrait-dialog')">
<p:graphicImage
id="portrait"
style="max-height: 85vh;"
a:onload="PF('portrait-dialog').show();"
value="/files#{portraits.portrait.getPath('_810x1440.jpg')}"
onclick="PF('portrait-dialog').hide();" />
</p:dialog>
Now my dialog waits for the image file to download before displaying and centering and all is well.
The following is a link to my original question in the PrimeFaces forum.
https://forum.primefaces.org/viewtopic.php?f=3&t=53248

Primefaces weird behaviour with datatable, overlayPanel and filter/sort

I'm having some trouble with primefaces datatables and dynamic overlay for each row.
Basically I have a main datatable containing a certain number of rows. For each row, I have a button and a linked overlay that, when clicked, shows a small datatable in the overlay (it lists the lasts changes concerning the row).
Here is the simplified code:
//the main datatable
<p:dataTable id="terminauxDataTable" var="terminalBean" widgetVar="dataTableWidgetVar" value="#{cc.attrs.listAllTerminals}"
filteredValue="#{cc.attrs.listFilteredTerminals}">
...
<p:columnGroup>
<p:row>
<p:commandButton id="changelogButton"
type="button"/>
<p:overlayPanel id="changelogPanel" for="changelogButton"
dynamic="true">
//the small datatable for each row
<p:dataTable var="changelog" value="#{terminalBean.lastChangelogs}">
<p:column headerText="#{msg['commun.changelog.table.label.date']}">
<h:outputText value="#{changelog.dateHr}">
<f:converter converterId="dateTimeConverter" />
</h:outputText>
</p:column>
... some other colums
</p:dataTable>
</p:overlayPanel>
</p:row></p:column></p:datatable>
everything works fine at first sight. When I click on any button i do get the content that I want to load. it's supposed to look like this :
http://i.stack.imgur.com/n9GrW.png
(sorry, cannot post image directly)
Problems start to arise as soon as I make any filtering od sorting on the main datatable.
If a specific button was never clicked since page load, the overlay and the contained datatable are load successfuly. It dosen't matter if I applied a filter or a sort.
If I already clicked a button at least once and then I apply a sort/filter, if I try to click again on the button the overlay is shown but is empty, there is no datatable inside.
here is an exemple of a click after a filter on a button that was clicked before :
http://i.stack.imgur.com/eLGLo.png
Do you have any lead on how to address this problem ?
Thank you
Using the overlay opitimally with a datatable, requires a little different approach as can be seen in the PrimeFaces showcase of the overlayPanel
You need to put the overlayPanel outside the datatable, put a updatable container in there, e.g. an outputPanel and on the button in your column, update the panel and call the show function of the overlay panel with a specific parameter. Something like this:
<p:dataTable>
....
<p:column style="width:32px;text-align: center">
<p:commandButton update=":form:terminalDetail" oncomplete="PF('myTerminalOP').show('#{component.clientId}')" icon="ui-icon-search" title="Details">
<f:setPropertyActionListener value="#{selectedTerminal}" target="#{mySelectionView.selectedTerminal}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:overlayPanel widgetVar="myOP" showEffect="fade" hideEffect="fade" dismissable="false" showCloseIcon="true">
<p:outputPanel id="terminalDetail" style="text-align:center;">
...
</p:outputPanel>
</p:overlayPanel>
(Disclaimer: done on my phone, so typos may be there)
On latest version of primeng we can do this.
Triggering the event based on element #id. By doing the toggle from typescript, I was able to pin point the element I need to attach the overlay panel to.
HTML:
<div>
<p-table>
<--loop the data-->
<button pButton (click)="showOP($event, rowwiseData, 'button'+rowIndex)" [id]="'button'+rowIndex"></button>
</p-table>
</div>
<--outside of the table add the overlay menu-->
<p-menu #menu [popup]="true" [model]="panelData"></p-menu>
TS File:
panelData: any;
#ViewChild('menu', {static: false}) op: OverlayPanel;
<!--Call and point the event to the correct element using unique #id-->
showOverlayPanel($event: MouseEvent, rowwiseData: any, id:string) {
this.panelData = rowwiseData;
this.op.toggle($event,document.getElementById(id));
}

commandButton for removing images from p:galleria

I am using Primefaces 5.0.2 with Glassfish 4 (Mojarra 2.2.0).
I've been trying to add a command button to delete/remove the selected image in a p:galleria component. I tried adding a button within the galleria component like this:
<p:galleria id="images" value="#{someBean.images}" var="image">
<p:graphicImage value="#{image}"/>
<p:commandButton icon="ui-icon-trash" title="Delete #{image}" style="position:absolute; top:0; right:0; z-index:10;"
actionListener="#{someBean.deleteImage(image)}"
update="growl images" />
</p:galleria>
I can display the image path fine within the button, but passing the image parameter in the EL Expression #{someBean.deleteImage(image)} does not work as expected.
The issue I have is that when deleteImage is called the image parameter (String) is always empty instead of containing the image name. However, title="Delete #{image}" displays fine, so I suspect image isn't resolved correctly within the actionListener or action attributes.
If I enter a literal string in the xhtml, e.g. #{someBean.deleteImage('deleteme')} it is passed correctly. Passing null also gives an empty string.
someBean.images is a List<String> (image paths).
I am at a loss :/ could anyone point me in the right direction? Is this a bug or am I doing something wrong?
I have also thought about adding a button outside the galleria component, but I am unclear as to how to determine the selected image without having to modify the p:galleria component.
There is also an unanswered question about this (1yr old) How to get the selected image from <p:galleria
Update:
Appending "test" to image using ui:param or c:set will actually give me the string "test" within the deleteImage method, but the h:outputText component correctly renders the value of image with "test" appended. This suggests to me that they are rendered at different times - and the commandButton is rendered at a time when image is null?
<p:galleria id="images" value="#{someBean.images}" var="image">
<p:graphicImage value="#{image}"/>
<ui:param name="img" value="#{image}test"/>
<h:outputText value="#{img}"/>
<p:commandButton icon="ui-icon-trash" title="Delete #{image}" style="position:absolute; top:0; right:0; z-index:10;"
actionListener="#{someBean.deleteImage(img)}"/>
</p:galleria>
Update 2
This could be related to a similar issue in Primefaces Extensions - maybe it is a bug after all. http://forum.primefaces.org/viewtopic.php?f=14&t=39992
I also started a thread in the PF forum: http://forum.primefaces.org/viewtopic.php?f=3&t=40055
<p:galleria id="photoGalleria"
panelHeight="400"
panelWidth="450"
widgetVar="photoGalleriaWidgetVar"
style="width: 100%;"
autoPlay="false"
value="#{partEditBean.selectedPart.partPictures}" var="img">
<p:panelGrid columns="1" styleClass="wf" style="text-align: center;">
<p:commandButton id="delete_pic_button"
update="#form"
value="#{msg['part_view.delete']}" process="#this"
actionListener="#{partImageEditBean.deleteListener}">
<f:param name="pic_id" value="#{img.picId}"/>
</p:commandButton>
</p:panelGrid>
<p:graphicImage styleClass="wf galleriaOver" value="#{img.picUrlPath}"
title="#{partEditBean.selectedPart.partTreeNode.partPathName}"
onclick="window.open('#{img.picUrlPath}','_blank');"/>
</p:galleria>
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("pic_id")

JSF insert space between components in same <div>

Good Evening, i want to know how to insert space between JSF components that lies in same <div> without using <h:outputText value=" " /> i used it and in order to insert the desired space that i want i repeated these tag around 50 times! what are the alternative approaches to do that, these is the <div> :
<div
style="width: 100%; font-size: 20px; line-height: 30px; background-color: gray">
<h:outputText value="–" />
<h:outputLabel value="Notifications ">
<h:graphicImage
value="/resources/images/lunapic_136698680056094_2.gif" />
</h:outputLabel>
/// insert space here
<h:outputLink id="lnk" value="#">
<h:outputText value="Welcome,Islam"></h:outputText>
</h:outputLink>
<p:tooltip for="lnk">
<p:graphicImage value="/resources/images/sofa.png" />
</p:tooltip>
</div>
This is normally to be achieved using CSS, e.g. via the margin property. CSS works on HTML and JSF is in the context of the current question merely a HTML code generator. You should ignore the JSF part in the question and concentrate on the JSF-generated HTML output in order to achieve the requirement. You can see it by rightclick, View Source in a webbrowser. If the HTML needs some altering, then change the JSF source code in such way that it generates exactly the desired HTML.
E.g.
<h:outputLabel value="Notifications" style="margin-bottom: 100px;">
(please note that using style is a poor practice; CSS should preferably be declared in a .css file which you import via <h:outputStylesheet> and reference via styleClass attribute)
Again, this all has nothing to do with JSF. JSF is in the context of this question merely a HTML code generator. If you're brand new to basic HTML/CSS and thus doesn't exactly understand what JSF is producing, then I strongly recommend to take a JSF-pause and learn those basics first.
Unrelated to the concrete problem, the <h:outputLabel> generates a HTML <label> element, but you don't seem to have any HTML input element associated with it. You're in essence abusing the label element for the wrong purpose. Understanding basic HTML and how to write semantic HTML and knowing what HTML output those JSF components exactly generate should push you far in the right direction. In this particular case, you should likely be using <h:outputText> instead.
To insert spaces between components in the same line, you can use img tag with a 1x1 clear image. (Note: this should be the last resort until other options exhausted, see discussion below)
<img width="100" height="10" src="/path-to/dot_clear.gif" />
e.g.
<img width="100" height="10" src="https://raw.githubusercontent.com/jonathanluo/jsf/master/images/dot_clear.gif" />
Enter desired width; for height any number between 1 to 10 will do.
By default, the unit of width and height is pixel
To get a copy of the dot clear image and save it to local resources from https://raw.githubusercontent.com/jonathanluo/jsf/master/images/dot_clear.gif
Right click on the content area and Save as...

Richfaces ModalPanel - title background image

I need to use an image as background in a modalPanel title.
I'm using JSF + Richfaces.
Is is possible?
Thanks
This should be possible by inserting a header facet into the modal panel with the content that you wish to appear in the panel.
<f:facet name="header">
<div style="background: url("/bla/foo.png") repeat-x scroll 50% 50% #F36D21;" />
</f:facet>
On the inside you can just declare a div with a repeating background image as a backdrop to other content in your facet header.

Resources