I used an ice:dataTable component to display data, somehow there was a default onscroll event in the target div which doesn't make any sense to me and it had brought some positioning problems to other float elements within the page. I want to disable this action, but I didn't find any approach to control this.
It called the function below:
var input = document.getElementById('targetId'); clearTimeout(ice.pid);
ice.pid = setTimeout(function() {
input.value =
document.getElementById('targetId_scroll').scrollTop;
window.iceSubmitPartial(null, input, event);
}, 400);
I had a similar problem with ICEFaces and as we upgraded the JSF and ICEFaces versions the best solution was to change the tags:
ice:dataTable tag to ace:dataTable and the columns inside from ice:column to ace:column.
But, if you didn't upgrade ICEFaces version, I guess you could use a JavaScript or jQuery in some point of your code removing the onscroll attribute, like:
document._getElementsByXPath("//div[contains(#onscroll,'scroll')]")[0].removeAttribute("onscroll")
This one isn't a good one, just a example, cause you can remove scroll from other tables.
jQuery('.myClass div[id$="_scroll"]')[0].removeAttribute("onscroll")
Related
Maybe it's a dumb question, but in Primefaces's <p:dialog> there's property which called appendTo which described in manual as:
Appends the dialog to the element defined by the given search
expression.
I can't realize what it useful for?
From the PrimeFaces User Guide (currently p. 185):
Do not place dialog inside tables, containers likes divs with relative positioning or with nonvisible
overflow defined, in cases like these functionality might be broken. This is not a limitation
but a result of DOM model. For example dialog inside a layout unit, tabview, accordion are a
couple of examples. Same applies to confirmDialog as well.
You can overcome this by using appendTo="#(body)" and your dialog will be attached as a child of the <body> node.
One of the main dialog option is modal and you could quickly end up with your dialog behind the overlay if you are not using appendTo as shown below:
See also http://forum.primefaces.org/viewtopic.php?f=3&t=16504
Notes:
Before PrimeFaces 5.0, the attribute to set was appendToBody="true". This was changed for 5.0.
If your dialog contains some buttons don't forget to surround them by <h:form> (see Proper Construct for Primefaces Dialog)
The PrimeFaces docs are a bit sparse on this point. appendToBody / appendTo (before 5.0) solves (or tries to solve) a problem where a PrimeFaces component does not get the right z-Index, meaning it does not appear before or behind other elements the way it should. However, this feature is problematic because it can cause other problems like p:commandbutton action doesn't work inside p:dialog
tl;dr:
Do not use appendTo / appendToBody. Instead, Dialogs (along with ConfirmDialog and OverlayPanel) should always be at the root of the component hierarchy, as a direct descendant of <h:body>. This will make them work reliably. In that case using appendTo / appendToBody is unnecessary.
One good way to accomplish this is to have one (or multiple) separate XHTML files for these components ("dialogs.xhtml"), which then gets included in your main XHTML file or template (for example using <ui:include>). Another solution is to use a <ui:define> in combination with a <ui:insert> if you want the dialogs to remain in the XHTML file where they are used.
Read on for details :-)
The problem
Some PrimeFaces components (such as dialogs) should be be displayed on top of other elements.
For example:
If you use <p:dialog ...modal="true">, and make the dialog visible, you get a dialog in the foreground, appearing above the rest of the page, with the rest of the page covered by a transparent layer.
You can see this for example in the PF Showcase for dialogs (button "Modal").
Behind the scenes, i.e. in the page's DOM, two things happen:
a new <div> (the "modal overlay") is created at the end of the <body>. This div gets the CSS styles: z-index: 1000; position: absolute; opacity: .30;. This makes it transparent and covering the whole page, to get the "modal" effect.
the (existing, but invisible) div of the dialog itself is made visible, and gets the styling z-index: 1001; position:fixed;. Note the z-index is one larger than the modal overlay, thus the dialog appears above the overlay.
However, this does not always work. The reason for this is an aspect of CSS called the stacking context. The details are a bit complex, but basically it says that the z-index of a page element is only compared to other elements inside the same parent element. In particular, an element may appear behind another element even though it has a higher z-index, if the element with the high z-index is contained in an element with a lower z-index.
The short (safe) version is: To be certain that z-index works as expected, all concerned elements should be siblings in the DOM.
Now, in this particular situation, the modal overlay must be right at the top of the DOM hierarchy (i.e. inside <body>), otherwise it cannot reliably appear above the rest of the page. However, the div of the dialog itself is somewhere deeper in the DOM (corresponding to the position of the <p:dialog> tag in the source XHTML). Now we have a problem.
In practice, this means that the overlay may appear above the dialog, thus obscuring and blocking it. Similarly, if the dialog is not modal, it may appear behind other elements in the page.
The insidious thing about this problem is that it depends on the structure of the rest of the page (specifically, whether the rest of the page uses CSS that creates a new stacking context). So <p:dialog> may appear to work initially, then suddenly shows incorrectly after a change elsewhere.
How 'appendTo' helps
As explained above, the problem occurs because the HTML rendered for the PrimeFaces component is somewhere deep down in the DOM, while it would need to be a direct child of <body> for the z-index to work correctly.
When appendToBody / appendTo is used, PrimeFaces will include Javascript in the rendered page which simply moves the DOM node of the PrimeFaces component to the end of <body> (using JQuery's appendTo function). That way the component is in the right place in the DOM, and z-index works.
The problem with using 'appendTo'
While the DOM reorganization performed by appendTo solves the problem with CSS and z-index, it introduces another (potential) problem:
The client-side DOM no longer corresponds to the server-side page state maintained by JSF (called the view).
Now, one of the central features of JSF is that it expects the client-side HTML/DOM structure to correspond to the the server-side view - after all, JSF constructed the HTML from that view. If that rule is violated (usually by manipulating the DOM client-side), you get all kinds of weird problems, such as JSF ignoring form fields or values in a submit, or overwriting part of your modifications on AJAX updates.
In this case, the problems caused by moving the DOM node of the PrimeFaces component include:
If the PrimeFaces component is part of a <h:form>, it will not work properly (because it will not be inside the <form> tag client-side because of the moving).
This is actually mentioned in the PrimeFaces docs, along with the workaround: Instead of putting the component into a form, put a form inside the component - then the form will move with the component.
If the area where JSF originally rendered the PrimeFaces component is updated using JSF's AJAX feature, JSF will remove area to update from the DOM, then render the component again, as it does not know it was moved elsewhere.
In old versions of PrimeFaces, this caused the component to appear in the DOM twice (with the same id), which caused problems with later submits. This was fixed for PrimeFaces 4.0 ( Issue 5636: Dialog appendToBody & dynamic doesn't remove the old dom element ), but re-occurred in 5.0 (issue #367).
This shows that this kind of DOM manipulation "behind JSF's back" is rather risky and should be avoided - thus my advice to not use appendTo / appendToBody.
I'm writing a Primefaces 5.1 portlet.
It consists in a unique page containing a panelMenu, and I need that it starts with any panel collapsed everytime a user change page (on page loading).
But, if I open a panel, then change page, it will start showing that panel still opened.
I wasn't able to find any option to achieve this goal (e.g. collapsed=true, ignoreCookie=true or something similar).
The only solution I found was the following Javascript code:
PrimeFaces.widgets.myPanelMenu.collapseRootSubmenu(PrimeFaces.widgets.myPanelMenu.headers);
The problem is that this code will collapse any opened panel (so on page loading user is able to see panel menu collapsing animation) but it seems it doesn't store this state in its cookie/localstorage... the result is that on any page loading user can see this animation.
I'm sure it doesn't save its state, because the only way to "solve" the problem is to manually re-open and re-collapse the panels... then, on following page change, these menus start closed (and there is no animation).
I also tried to use PrimeFaces.widgets.sideMenuPanel.saveState() after collapsing, but with no success.
Do you have any idea about?
Thank you...
I found a solution to the problem.
If you read my discussion with Kukeltje (comments on my question), you will find that latest Primefaces' versions will solve the problem.
Otherwise, if you want to avoid upgrade or modify sources, and you need a quick fix based on Javascript only please read the following part of the answer.
It directly works on the component's state using JavaScript.
First of all you need to have a variable reference to your component:
<p:panelMenu model="#{menuBackingBean.menuModel}" widgetVar="sidePanelMenu" />
Then you should add the following JS code on document ready:
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
// following line is commented because it never should be necessary is not necessary (unless unexpected situation I never verified)
//clearSidePanelMenuPreferences();
// 2. Call the "clear preferences" actions on click on two tpe of links: first level are the panel link (used to open/close the menu) and second level are the destination links
// We need to fork also on the first level links to be sure it works after user clicks there then exit from the page in another way
panelMenu.headers.children("a").click(function(){setTimeout(clearSidePanelMenuPreferences, 500)}); // setTimeout is necessary because this event should be fired after preferences are written
panelMenu.headers.siblings().find("a").click(function(){clearSidePanelMenuPreferences();});
The function called to clear preferences are the following:
function clearSidePanelMenuPreferences() {
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState(); // store this information
}
Hope it helps
Please check this block of code
PF('myPanelMenu').headers.each(
function(){
var header = jQuery(this);
PF('myPanelMenu').collapseRootSubmenu(header);
header.removeClass('ui-state-hover');
}
);
I prefer to do this in order to execute this method only once and keep the menu option selected.
$(document).ready(function() {
if(location.pathname == "/cotizador/" || location.pathname == "/cotizador/faces/login.xhtml"){
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState();
}
});
I have a View which extends GridLayout and has a 2x2 - Matrix.
Now I want to programmatically remove a component in one of the cells of the GridLayout with:
this.removeComponent( component );
But the component doesn't get removed at least the browser view doesn't get updated.
I also used:
this.removeComponent( col , row , component );
But the problem is still the same.
UPDATE: When I first do a component count :
int c = this.getComponentCount();
I get four.
After the removeComponent I get THREE - so it get's removed but the browser doesn't reflect this.
Any ideas what the problem could be?
Your problem is a sync problem, the client doesn't get notified from your server, so he doesn't know that this gridlayout has changed.
So the client is not updating his view.
To fix this, you can use #Push annotation or add a "refresh" button.
Push (see Doc) allows you to call client actions from the server to update view. The problem you are actually having is that your element is not removed after a client action, so the client is not waiting for a content update, so nothing is updated.
How do I disable keyboard entry in a primefaces extensions timePicker inside a primefaces datatable ? There is no property by default like p:calendar.
Can i do it via js ?
I have to either disable keyboard entry or manipulate the component such that it hides the popup and the user can only type in values. Tried the latter using css but it failed. Please help.
Thanks !
As far as I am aware you can't do it on the component itself...YET.
What has worked for me with JSF regarding a similar issue was the Javascript/Jquery approach. For instance you take an Id or a class of certain component you want to disable the keyboard on and do the following.
$(document).ready(function() {
$("#yourComponentId").keydown(false);
});
or this:
...
$(".yourComponentClassname").on("keydown keypress keyup", false);
...
As far as I am aware if you give the component an attribute like:
... readonly = true ...
your backing bean will ignore it unless you mess around with:
FacesContext#getRenderResponse();
Hope this helps a bit.
when we type into autoComplete, primefaces automatically highlighted first shown item. so when we press enter key that item will be selected. how can i change the behavior of enter key, so when it pressed, just entered text be submitted in backing bean property.
I know we can hit ESC button then continue but but user don't like it.
I am using primefaces 5.0 & jsf 2.1.11
What helped me to solve the same issue where the answers here and here. Basically, you have to override 2 different behaviours.
First one is the default selection of the first result, that can be achieved adding this to your autocomplete (as stated by the accepted answer in the first link, available in primefaces for versions 5.1.5, 5.0.14 and 5.2):
autoHighlight="false"
The second thing you want to override is the behaviour when Enter is pressed, as you want the form that contains the autocomplete to be submitted. For doing so, just add this code to either the containing form or the autocomplete:
onkeyup="if (event.keyCode == 13) {
document.getElementById('[searchFormId]:[submitButtonId]').click();
return false; }"
Change the ids between square brackets for your own ones and it's done.
PS: I know this is a rather old question but it still applies to the current version of primefaces (6.1 when this question was answered). And I also think it can help to have both changes combined in one answer.
Truth be told, this feels like a bug. Richfaces do that implicitly (submit on enter while suggesting). I haven't found an official fix so I did some research and turns out the simplest way is to override the JS function that resolves key presses. The whole autocomplete js is here. You just need to override the bindKeyEvents function so you declare it likewise:
PrimeFaces.widget.AutoComplete.prototype.bindKeyEvents = function () {
Then add the rest of the code for this specific function from the JS I mentioned before. I've omitted that code so it's more readable. Then you want to find a switch that resolves different keys that have some behavior mapped to them. And under the code:
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
Add something like:
if (highlightedItem.length == 0) {
document.getElementById("<your_form_id>").click();
_self.hide();
} else {
highlightedItem.click();
}
Also, make sure that you got forceSelection and the autohighlight off on the autocomplete component.
The problem in the JS is that even though you haven't selected any item from the suggestions it still triggers the event that tries to click the item... which doesn't even exist.
This is the simplest way as I said... you can also create your own autocomplete implementation and override the behavior there. But that's a lot of work and if you only need this one feature I suggest overriding the JS function.
In order to override the original JS with your custom one you need to make sure yours is loaded after the original one. To do that you can either use h:outputScript or simply just load the javascript like you're used to... but in the body (not the head).
Also there's probably a fancier way than having to specify the form id. But I just wasted too much time searching for a solution that I had to get it done real fast.