React to a MenuButton being clicked - jsf

We have code that periodically refreshes our document. We also have as part of the JSF page, menuButtons (primefaces), originaly as part of dataTable cell/s in a column. We want to disable the refresh when the menuButton is clicked (the menu is expanded), and re-enable it when the menuButton is closed (to prevent page refresh from closing menu).
I've attempted to catch menuButton events using java script, but to no avail. Part of the problem is that I do not know how to identify the JSF component uniquely from javascript, as ID does not seem to work when attempting to catch events. There also does not exist any satisfactory event attributes (as part of Primefaces menuButton) that I can hook up to javascript.
Below is the minimal code that I could extract. I have extracted the menu to be on its own (not part of dataTable) for simplicity, as the question still stands. I may have a reference to a bean and dictionary files in there, but you should get the idea:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:form id="virtualMachineTableForm">
<!-- Lazy load table -->
<p:remoteCommand name="lazyload"
update=":vmGroupTabs:virtualMachineTableForm:testMenu"
actionListener="#{backupGroupController.refreshHard()}" />
<!-- Refresh hard button -->
<p:commandButton id="refreshButton"
update=":vmGroupTabs:virtualMachineTableForm:testMenu"
icon="ui-icon-refresh"
immediate="true"
title="#{msg.action_refresh}"
actionListener="#{backupGroupController.refreshHard()}"/>
<p:menuButton
id="testMenu"
value="#{msg.menuButton_SelectItem}">
<p:menuitem
value="Toggle refresh"
onclick="toggleRefreshState()">
</p:menuitem>
</p:menuButton>
<!-- Poller -->
<p:poll interval="5" listener="#{backupGroupController.refreshSoft()}"
update=":vmGroupTabs:virtualMachineTableForm:testMenu" widgetVar="poll" />
</h:form>
<script type="text/javascript">
var toggleRefreshState = function(){
if (poll.isActive()) {
poll.stop();
alert("Poller stopped" );
}
else {
poll.start();
alert("Poller started" );
}
};
$(document).ready(function(){
poll.start();
setTimeout("lazyload();", 100);
});
//
// $("???SomeWayToIdentifyMenu???").on({
// onMenuOpen???: function(){
// alert("Opening menu - stopping refresh");
// }
// onMenuClose???: function(){
// alert("Closing menu - starting refresh");
// }
// });
</script>
</ui:composition>
Is it possible to catch menu open/close (or for that matter any) events for jsf primefaces menu buttons on the client side using Java script?
Is it possible to determine if the menubutton is open/closed for the purpose of disabling refresh to prevent menu from disappearing.
Your help appreciated, Thank you,
Werner

In the end it is all html, javascript and css. Javascript in PF is mainly jquery and all components have javascript code behind them to function on the client side.
There are several ways to plug into this. Attaching plain jquery event handlers to the right element (checkable via your browser developer tool and/or checking what the PrimeFaces javascript does) is an option, but you have to reapply them over and over again when e.g. ajax calls take place. Another option is to override the basic menu button functionality without changing the PF original source.
Since the code is open source, you can try to find the javascript source of the PrimeFaces MenuButton. It is in this case all defined in menu.js and this can be fairly easily looked at (and is cleanly written)
In there you can see all events that are added to the component and also if there e.g. are onBeforeShow handlers or not (some components in PrimeFaces have those, the MenuButton not which is unfortunate for you, but I've not seen a usecase like this up to now).
The downside of overriding the basic functionality unfortunatly is that this will then be true for all menu buttons. So you have to implement some logic to decide if you actually need to perform some custom action or not. There are several ways to do that, but the easiest in my opinion is to check for the presence of a specific style class (e.g. 'stopPoll').
Now to the actual overriding:
var oldPFShow = PrimeFaces.widget.MenuButton.prototype.show
PrimeFaces.widget.MenuButton.prototype.show = function() {
alert("before show");
oldPFShow.apply(this, arguments);
}
var oldPFHide = PrimeFaces.widget.MenuButton.prototype.hide
PrimeFaces.widget.MenuButton.prototype.hide = function() {
oldPFHide.apply(this, arguments);
alert("after hide");
}
(do not forget to call the original functions)
Where I put the alerts, you have to implement checking for the presence of a class or leave that out if you have one menu button on that page or want the behaviour for all menubuttons
Some general comments: (Will be removed later on, but difficult to format in the comments)
I've attempted to catch menuButton events using java script, but to no
avail.
Posting attempts can help, since sometimes you are close and just have some small oversight). In those cases it is easier to write an answer for people trying to give support
Part of the problem is that I do not know how to identify the
JSF component uniquely from javascript,
This is a generic PrimeFaces thing (and differs from component sets). Apply a widgetVar attribute and with PF('') you have a handle to the specific components.
And as you can see the explicit fact that you use a PrimeFaces menuButton is of the highest importance. Having a small piece of code (smaller then you have now, but compliments for the mcve) is confirmation of this (assumption is the mother of all... ) Adding 'javascript' as a very generic tag, often attracts the 'wrong' people, as does 'java' So please next time leave those out

The easiest way to achieve this is to add javascript to the menuButtons to change a global variable and have the periodic refresh read that global variable and act accordingly. As you have no code or indication what components you are using I can't get more specific then that. Here would be the javascript code I would expect to see
window.preventRefresh = false;
function doPeriodicRefresh() {
if(!preventRefresh) {
window.location.reload();
}
}
setInterval(doPeriodicRefresh, 60000);
function showMenu() {
window.preventRefresh = true;
menu.show();
}
function hideMenu() {
window.preventRefresh = false;
menu.hide();
}
Your mouseovers/mouseout for the menu should call showMenu and hideMenu, any parameters would have to be proxied through.
This also depends on how you are doing your periodic refresh. If you are using the refresh header or metatag I don't believe you will be able to stop these from javascript.

Related

Is it possible to show only the confirm, and not the cancel button icon in Prime Faces DataTable rowEditor?

Is it possible to show only the confirm, and not the cancel button icon in Prime Faces DataTable rowEditor?
I ended myself with this approach
As stated by #Kukeltje it's possible to manage similar problems on client using
some css to hide it (it is all html, css and javascript on the client).
I choose jquery to handle html, css, and javascript (I'm relatively new to jsf/primefaces but I read it's based on jquery).
So in managed bean I was able launch scripts like this:
PrimeFaces.current().executeScript("$('#myForm\\\\:myContainer .ui-row-editor-close').eq(-1).remove();");
or even in XHTML/JS script like this:
<h:outputScript library="js" name="myScripts.js" />
$(document).ready(function() {
$("#myForm\\:myContainer .ui-row-editor-close").last().remove();
});
Anyway with this approach you need to be carefull, any ajax call which update part of the page involved reset to default, so cancel button will re-appear.

ValueChangeEvents being fired only after other components are clicked

I'm trying to use an InputFile within JSF (1.1.7) and Apache Trinidad (1.0.11). I define a change event for it but the event is not being fired when I change the file selection but when I click on another component of the form.
Here is the jsp code:
<trh:body>
<tr:panelPage>
<tr:form usesUpload="true" id="myForm">
<tr:inputFile columns="80" id="archivo"
valueChangeListener="#{myBean.changeInputFile}"
immediate="true">
</tr:inputFile>
<tr:commandButton text="Begin"/>
</tr:form>
</tr:panelPage>
</trh:body>
Here is the relevant part of the bean:
public void changeInputFile(ValueChangeEvent event) {
UploadedFile f = (UploadedFile)event.getNewValue();
}
The code only enters into the myBean.changeInputFile method when I click the Begin button (having changed the file selection previously). I would like it to enter into myBean.changeInputFile when I change the selected file in the inputFile component.
Any idea why could be this happening?
Your expextation is wrong. The valuechangelistener is a server-side action that will fire when something is submitted to the server and effectively has a different value than it did before. It is NOT telling the component to behave like modern ajax (jsf 1.1.7 and its valuechangelistener predate the ajax era). The form value is only submitted to the server when you, well, in 'old' html terms use form submission like pressing a submit button (or use some javascript to trigger that like you would in the old plain html days). And since without pressing a button or the added javascript, nothing is submitted to the server the valuechangelistener will not spontaneously do something.
So the behaviour you see is exactly as it should be.

JSF 2.0 page navigation not working

I'm using JSF 2.0 in my web project. But navigation is not working properly, in my case. I think this problem arose due to changes in hierarchy of the files because action method is working fine. I'm attaching the snapshot to give idea about files' hierarchy.
If anyone could help to overcome this, I'll be very thankful.
You have to add ajax="false" to you primefaces commandButtons in order to perform navigation or use the simple <h:commandButton ...
if you want to use primefaces ajax button , you should sue redirect then,
like this
<p:commandButton action="home?faces-redirect=true" value="Redirect to home"/>
also look a t similar question over here:
PrimeFaces commandButton doesn't navigate or update
Upgrade to PrimeFaces 3.2. Then you'll be able to navigate by ajax. The update/render of #all was not supported before that version. If you can't upgrade, then you need to bring in the following JavaScript hack:
var originalPrimeFacesAjaxResponseFunction = PrimeFaces.ajax.AjaxResponse;
PrimeFaces.ajax.AjaxResponse = function(responseXML) {
var newViewRoot = $(responseXML.documentElement).find("update[id='javax.faces.ViewRoot']").text();
if (newViewRoot) {
document.open();
document.write(newViewRoot);
document.close();
}
else {
originalPrimeFacesAjaxResponseFunction.apply(this, arguments);
}
};
Put this in a .js file which you import in the very end of the <h:head> tag. E.g.
<h:head>
...
<h:outputScript name="js/primeFacesAll.js" />
</h:head>

How do I have the cursor placed in a dropdown field on page load using jsf?

when I load a page , the cursor must point to drop-down field , using jsf.I am new to JSF.
When the page is finished loading in webbrowser, JSF has already done its job of generating a bunch of HTML on the webserver and sending it to the webbrowser. It can't do any much more for you after that point. You need to use JavaScript for this job. It is able to execute code when the page is finished loading and it has access to all elements in the HTML DOM tree.
So, if you specify a fixed ID for the dropdown element in JSF,
<h:form id="myform">
<h:selectOneMenu id="mydropdown">
...
</h:form>
then you must be able to grab it by JavaScript:
var mydropdown = document.getElementById('myform:mydropdown');
In JavaScript, you can use element.focus() to set the focus on the element:
mydropdown.focus();
To get it to execute then the page is finished loading, you need to hook a function to window.onload:
window.onload = function() {
var mydropdown = document.getElementById('myform:mydropdown');
mydropdown.focus();
}
That's it. Put it in a <script> somewhere near the bottom of the <head> or a .js file which you include by <script src>.
JSF is a server side technology and this type of behavior requires Javascript. Try to write a Javascript to do this in a regular HTML page first. Once you have figured out how to do this you can try to use this script in your JSF page.

Set focus to specific JSF inputText on page load

I want to set focus on inputText field in JSF on page load. How can I implement this?
If you're already at HTML5 and JSF 2.2, use HTML5 autofocus attribute. In JSF 2.2 you can set it as a passthrough attribute.
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputText ... a:autofocus="true" />
You can even conditionally set it, you only need to make sure that the false condition evaluates to null, otherwise the attribute will still be rendered. It's a HTML boolean attribute, so only its presence is already the trigger regardless of its value. When the value is explicitly set to null, then JSF won't render the attribute in its entirety.
<h:inputText ... a:autofocus="#{component.valid ? null : true}" />
An alternative would be to throw in some JavaScript. Every input element has a focus() function. The below naive Vanilla JS approach focuses the first element of the first form.
window.onload = function() {
document.forms[0].elements[0].focus();
}
If you want to focus a specific input element during window load, then do:
window.onload = function() {
document.getElementById('formId:inputId').focus();
}
If you happen to have jQuery at hands, more fine grained checks could be done.
$(document).ready(function() {
$(":input:visible:enabled:first").focus()
});
In case you intend to execute it only after a postback, head to below related Q&A:
Set focus to inputText on validation error
Calling a JavaScript function from managed bean
Utility/component libraries may have builtin autofocus facilities. OmniFaces has a <o:highlight> which highlights all invalid inputs on postback and autofocuses the first one. PrimeFaces by default autofocuses the "last active" element on complete of an ajax request and has a <p:focus> for more fine grained control. See also below related Q&A:
OmniFaces highlight does not set focus with <p:ajax>
If you use primefaces, you can focus your input like this:
<p:focus for="inputId"/>

Resources