Primefaces autocomplete menu opens in the wrong spot - primefaces

I have dialog with some detail information. When dialog is opened informations are shown as noneditabile labels. User can open editabile grid pressing button which change render parameter to both panelGrid, noneditabile is set to flase and editabile to true.
In editable grid I have autocomplete component which menu is show on wrong spot. Left and top attributes for autocomplete menu are set relative to body, not to dialog (like top-left corner of dialog is on 0,0). That happens only when I open dialog for 1st time, if I close it and open again then menu is properly opened below textbox field.
<p:dialog ... appendTo="#(body)">
<h:form>
<p:outputPanel id="opX">
<p:panelGrid rendered="#{x}" >
// non editabile content
</p:panelGrid>
<p:panelGrid rendered="#{!x}" >
// editabile content
...
<p:autoComplete value="#{xBean.acValue}" completeMethod="#{xBean.acMenu}" />
...
</p:panelGrid>
</p:outputPanel>
<p:commandButton action="#{x=!x;}" process="#this" update="opX" />
</h:form>
</p:dialog>
Any idea why this is happening so?
Furthermore I have troubles with autocomplete which has columns in it when it's rendered afterwards (or update after some changes).
I get error:
itemLabel="#{sifra.value}": Property 'value' not found on type
java.lang.String
<p:autoComplete value="#{xBean.acValue}" completeMethod="#{xBean.acMenu}" var="sifra" itemValue="#{sifra.value}" itemLabel="#{sifra.value}" >
<p:column><b>#{sifra.value}</b></p:column>
<p:column>#{sifra.name}</p:column>
</p:autoComplete>
public List<GeneralListDto> acMenu(String inputValue) {
try {
GeneralListDto x = calling sme web service;
return x;
}
catch(Exception e){
...
}
}
public class GeneralListDto {
public GeneralListDto(){
}
public GeneralListDto(String n, String v, String d){
this.name = n;
this.value = v;
this.description = d;
}
private String value;
private String name;
private String description;
getter and setters
....
}

Unfortunately I couldn't reproduce your problem, but here's some tips:
Try to place the form outside the dialog
<h:form id="dialogForm">
<p:dialog widgetVar="dlgWV" appendToBody="true">
</p:dialog>
</h:form>
try to update the form before opening the dialog, in this way it might "recalculate the position"
<p:commandButton update=":dialogForm" oncomplete="dlgWV.open()" />
As for itemLabel="#{sifra.value}": Property 'value' not found on type java.lang.String.
You need to implement a converter for sifra object.
Sometimes if you have too many results in the autocomplete suggestion panel, you might run into view problems, like the position and some unvisible items, in this case you have two solutions, CSS or overrride the position of the panel.
CSS
.ui-autocomplete-panel {
max-width: 400px;
z-index: 2012;
overflow:auto;
height: 200px;
}
JS
PrimeFaces.widget.AutoComplete.prototype.alignPanel = function() {
var fixedPosition = this.panel.css('position') == 'fixed',
win = $(window),
positionOffset = fixedPosition ? '-' + win.scrollLeft() + ' -' + win.scrollTop() : null,
panelWidth = null;
if(this.cfg.multiple) {
panelWidth = this.multiItemContainer.innerWidth() - (this.input.position().left - this.multiItemContainer.position().left);
}
else {
panelWidth = this.input.innerWidth();
}
this.panel.css({
left:'',
top:'',
width: panelWidth
})
.position({
my: 'left top'
,at: 'left bottom'
,of: this.input
,collision: 'none',
offset : positionOffset
});
}
Hope this helps.

Related

Combine Drag&Drop and Reorder in a p:dataTable

I need to combine Drag and Drop and Reorder on a DataTable row. I know that there are ways to do this on different columns (like one column for the reorder, the other one for Drag and Drop), but I need to do it on one Element.
I tried different ways, but nothing worked. The Problem is, that once the reordering is triggered, I can't drop it in the area. It always returns to the end of the table.
Getting the mouse position wouldn't work, because i need to make it responsive and usable for mobile devices.
HTML:
<p:fieldset id="availableCarsField" legend="Available Cars">
<p:dataTable id="availableCars"
var="car"
widgetVar="widgetVarAvailableCars"
draggableRows="true"
value="#{dndCarsView.cars}">
<p:column id="dragColumn"style="width:20px;">
<h:outputText id="test" value="#{car.id}"/>
<p:draggable helper="clone" revert="true"/>
</p:column>
</p:dataTable>
</p:fieldset>
<!-- ........................... DROP ...........................-->
<p:fieldset id="selectedCars" legend="Selected Cars">
<p:outputPanel id="dropArea">
<h:outputText value="!!!Drop here!!!"
rendered="#{empty dndCarsView.droppedCars}"
style="font-size:24px;"/>
<p:dataTable id="selectedCarsTable"
var="car"
value="#{dndCarsView.droppedCars}"
rendered="#{not empty dndCarsView.droppedCars}">
<p:column headerText="Id">
<h:outputText value="#{car.id}"/>
</p:column>
</p:dataTable>
</p:outputPanel>
</p:fieldset>
<p:droppable for="selectedCars"
tolerance="touch"
activeStyleClass="ui-state-highlight"
onDrop="handleDrop"
datasource="availableCars">
<p:ajax listener="#{dndCarsView.onCarDrop}"
process="#form"
update="dropArea availableCars"/>
</p:droppable>
JS:
function handleDrop(event, ui) {
var droppedCar = ui.draggable;
droppedCar.fadeOut('fast');
}
Bean (in case it's required):
public class DNDCarsView implements Serializable {
private List<Car> cars;
private List<Car> droppedCars;
#PostConstruct
public void init() {
cars = createCars(9);
droppedCars = new ArrayList<>();
}
public List<Car> createCars(int size) {
List<Car> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(new Car("" + i, "Brand" + i, i * 2000, "Color" + i));
}
return list;
}
public void onCarDrop(DragDropEvent ddEvent) {
Object car = ddEvent.getData();
droppedCars.add((Car) car);
cars.remove(car);
}
public void onReorder(ReorderEvent event) {
Car car = cars.get(event.getFromIndex());
cars.add(event.getToIndex(), car);
cars.remove(event.getFromIndex());
}
//Getter & Setter
}
Is there anyway to combine these two and get this running?
Thanks in advance
Edit:
I want to reorder the rows inside the DataTable and also be able to drop the dragged row into the fieldset.
Primefaces 6.2.12
JSF 2.2
Edit 2:
After month of trying I haven't found a good solution for my problem. Just thought, that I might share this here, if someone else deals with this problem.
I seems like there is no way to realize Drag&Drop in combination with columnreorder on one element (in my case p:column). The problem is, that always the reorderevent is triggered when dragged. When dropped into the droparea, the dragId of the dragged element is null (because we started with the reorder-event but ended with the event for drag and drop)
Due to the fact that I wasn't allowed to change anything which wasn't my class I didn't manage to fix this. I ended up to separate the actions onto two elementes. So I made a drag handle where the user can drag the element into the droparea and realized the reorder on the column.
If I was blind and someone knows an answer to this feel free to write. Maybe it might help someone. At least it would be interesting whether there is a way to do so

p:datascroller only lazyload one time

We have implement the datascroller from primefaces and extend it with lazy=true this works fine for the first lazy loading. But when I scroll down no event is fired from Frontend. The Backend works as expected.
I test it with changing the chunk size and get a better understanding what is happen in the backend code. We override the load function what primefaces is calling when you reach the end of page. I changed the code to not lazyloading by scrolling, therefor i implement a button to load the next chunk when you click the button. But Button disappear after clicking it once.
Xhtml:
<p:dataScroller value="#{stakeholderOverviewController.model}" var="stakeholder" chunkSize="50" lazy="true" rowIndexVar="test">
<f:facet name="header">
Scroll Down to Load More Cars
</f:facet>
<f:facet name="loader">
<p:commandButton type="button" value="More" icon="pi pi-chevron-circle-down"/>
</f:facet>
<h:panelGrid columns="2" style="width:100%" columnClasses="logo,detail">
<p:outputPanel>
<h:panelGrid columns="2" cellpadding="5">
<h:outputText value="Id:" />
<h:outputText value="#{stakeholder.lastname}" style="font-weight: bold"/>
<h:outputText value="Year:" />
<h:outputText value="#{stakeholder.firstname}" style="font-weight: bold"/>
</h:panelGrid>
</p:outputPanel>
</h:panelGrid>
<ui:include rendered="#{empty stakeholder}" src="/WEB-INF/compositions/stakeholderEmptyModel.xhtml" />
</p:dataScroller>
there is the backend code for Controller:
public StakeholderOverviewController() {
model = new LazyDataModel<StakeholderSearchWrapper>() {
#Override
public List<StakeholderSearchWrapper> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map filters) {
List<StakeholderSearchWrapper> execQuery = execQuery(first, pageSize);
return execQuery;
}
};
model.setRowCount(0);
}
....
protected synchronized List<StakeholderSearchWrapper> execQuery(int first, int pageSize) {
if (tmpfirst != first || tmppageSize != pageSize || reExecQuery) {
reExecQuery = false;
tmpfirst = first;
tmppageSize = pageSize;
tmpModel = new LinkedList<>();
// Query for stakeholder
queryresponse = stakeholderService.findByLastnameOrFirstmanOwnerOrShare(getSearchText(), getClientId(),
first, pageSize, selectedFacets, nameSort[getSort()]);
setFacets(queryresponse.getFacetFields());
Set<String> stakeholderIds = new HashSet<String>();
// convert for view
for (SolrDocument details : queryresponse.getResults()) {
StakeholderSearchWrapper stakeholderSearchWrapper = new StakeholderSearchWrapper(details);
tmpModel.add(stakeholderSearchWrapper);
stakeholderIds.add(stakeholderSearchWrapper.getId());
}
historyCount = stakeholderService.countHistoryEntryByStakeholders(stakeholderIds);
notesCount = stakeholderService.countNoteEntriesByStakeholders(stakeholderIds);
assignedProjects = projectService.findByStakeholderIds(stakeholderIds);
for(StakeholderSearchWrapper dao : tmpModel) {
dao.setHistoryCount(getHistoryCount(dao.getId()));
dao.setNoteCount(getNoteEntriesCount(dao.getId()));
dao.setProjects(getAssignedProjects(dao.getId()));
}
SolrDocumentList result = queryresponse.getResults();
int numFound = (int) result.getNumFound();
return tmpModel;
} else {
return tmpModel;
}
}
What i want is that the lazy loading dont fire only once. It should fire as often as needed. I dont know where i have to set some variable to do this. When im debuging the current code the load function is only requested at the first run of the page refresh and than one lazy loading is called but then nothing happens.
I think I realized the trick. Check the line:
model.setRowCount(0);
Instead, set the model row count properly using the max amount of data you want to display:
int totalNumberOfRegisters = this.count(/* relevant paramenters*/);
model.setRowCount(totalNumberOfRegisters);

Multiple dialogs with ajaxExceptionHandler on the same page

I have a xhtml page with several dialogs declared within it
<ui:include src="/pages/dialogs/dialog1.xhtml"></ui:include>
<ui:include src="/pages/dialogs/dialog2.xhtml"></ui:include>
...
Dialogs are dynamic="true" and each dialog has ajaxExceptionHandler
<p:ajaxExceptionHandler update="exceptionDialog" onexception="PF('exceptionDialog').show();" />
<p:dialog widgetVar="exceptionDialog" id="exceptionDialog">...</p:dialog>
When some dialog opens and exception occures after some action nothing happens. ExceptionDialog is not shown.
The problem is that <p:ajaxExceptionHandler> created after dialog is included <ui:include> in the page and it is too early. You need it to be created when dialog shows up so you nead to create it dinamicly in managed bean.
In each dialog do this
Delete <p:ajaxExceptionHandler> tag.
And add
...
<h:panelGroup id="ajaxExceptionHandlerPlaceholder">
</h:panelGroup>
<p:outputLabel id="exceptionMessage" value="#{pfExceptionHandler.message}" style="color: red" />
<script>
createAjaxExceptionHandlerCommand();
</script>
</p:dialog>
In managed bean add this method
public void createAjaxExceptionHandler() {
AjaxExceptionHandler aeh = new AjaxExceptionHandler();
aeh.setType( null );
aeh.setUpdate( "exceptionMessage" );
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
final UIComponent[] found = new UIComponent[1];
root.visitTree( new FullVisitContext( context ), new VisitCallback() {
#Override
public VisitResult visit( VisitContext context, UIComponent component ) {
if ( component.getId().equals( "ajaxExceptionHandlerPlaceholder" ) ) {
found[0] = component;
return VisitResult.COMPLETE;
}
return VisitResult.ACCEPT;
}
} );
found[0].getChildren().add( aeh );
}

PrimeFaces <f:attribute not working correctly with p:galleria attribute

I have issue when trying to make command link from inside p:galleria component
The problem is despite the fact at run time the link value value="Show present #{present.name} #{present.presentId}" contains the correct value of the id as example value="Show present Foo 1" , when pressing the command link it sends the wrong id of the second object every time
<h:form>
<p:galleria value="#{presentBean.allPresentList}" var="present" panelWidth="500" panelHeight="313" showCaption="true">
<f:facet name="content">
<h:commandLink value="Show present #{present.name} #{present.presentId}" action="pretty:present" actionListener="#{presentBean.setPresentObj}">
<f:attribute name="present" value="#{present.presentId}"/>
</h:commandLink>
</f:facet>
</p:galleria>
</h:form>
#ManagedBean(name="presentBean")
#SessionScoped
public class PresentBean implements Serializable{
ArrayList<Present> allUserPresentList = new ArrayList<Present>();
#PostConstruct
private void usersPresent(){
PresentDao presentDao = new PresentDaoImpl();
allPresentList = (ArrayList<Present>) presentDao.findAllPresents();
}
public ArrayList<Present> getAllUserPresentList() {
return allUserPresentList;
}
public void setAllUserPresentList(ArrayList<Present> allUserPresentList) {
this.allUserPresentList = allUserPresentList;
}
private String presentId ;
public String getPresentId() {
return presentId;
}
public void setPresentId(String presentId) {
this.presentId = presentId;
}
public void setPresentObj(ActionEvent ev){
Object presentOb = ev.getComponent().getAttributes().get("present");
if(presentOb != null){
this.presentId = (String) presentOb;
}else{
presentId = null ;
}
}
}
You need to use a setPropertyActionListener instead of <f:attribute name="present" value="#{present.presentId}"/> as the f:attribute tag is only evaluated when the component is created (only once) not when the component generates html based on the iterated rows.
So you'll need to instead use:
<f:setPropertyActionListener target="#{presentBean.presentId}" value="#{present.presentId}" />
That will set the value of the presentId in your managed bean, so in your action method you can just access the presentId itself already without having to work it out.
Alternatively if you're using a later version of JSF (using Servlet 3.0 or above), then you could create a method in the managed bean which takes the presentId or even the present object as a parameter
e.g. in your managed bean:
public void myAction(Present p){
//do whatever you want with the Present object
}
and in your .xhtml:
<h:commandLink value="Show present #{present.name} #{present.presentId}" actionListener="#{presentBean.myAction(present)}">
</h:commandLink>

PrimeFaces open dialog several times with rendered attribute

I try to implement a dialog box accessible everywhere in my project and I was wondering if this solution is possible.
The dialog is included in the template of my project. For example, where I am on the login page, I would like to show the dialog when the button "Login" is clicked and the authentication is successful. So I catch the bean linked to the dialog with:
getFacesContext().getELContext().getELResolver().getValue(getFacesContext().getELContext(), null, beanName);
and I set the "show" argument. (have a look below)
The first time, it's working. When I access the login page, the dialog is not rendered and when I click the button login, the attribute show is set, the page is updated and the dialog appears. But if I close it, I could not fire it again when I click again the button. (The dialog is rendered but not shown)
My dialog is like this (I have visible="true" cause I want to show each time it's rendered):
<h:form>
<p:dialog header="Dialog" widgetVar="myDialog" rendered="#{bean.show}" visible="true">
<p:ajax event="close" listener="#{bean.onClose}" />
...
</p:dialog>
</h:form>
The bean is in viewscope:
#ManagedBean(name = "bean")
#ViewScoped
public class MyBean {
private boolean show; // + Getters and Setters
#PostConstruct
public void init() {
this.show = false;
...
}
public void onClose() {
this.show = false;
}
}
And I can add that my LoginBean which is setting the show argument is in viewScope too.
Thanks