JSF p:remoteCommand and javascript event onbeforeunload - jsf-2

We have several web applications a user can login. On click on logout button some logic must be processed. The problem is that most users close the browser without clicking on logout button. I tried the following to call my logic on browser close:
Added the event "onbeforeunload" to my frameset. On browser close a logout function will be called.
Within my logout function I use the primefaces p:remoteCommand component to call a action listener on the server.
In current firefox version everything works fine but I have some problems with IE9. Closing a tab in IE9 calls my logic. Closing the browser doesn´t work. My JS function is called but the request to the server is not executed. Is there any way to solve this problem? BTW: I know that this is not an 100% solution but we need exactly this functionality. My function and p:remoteCommand looks like that.
function automaticLogout() {
handleAutomaticLogout();
alert('BlaBla');
}
<p:remoteCommand name="handleAutomaticLogout" actionListener="#{myBean.handleAutomaticLogout}" async="false" />

Do you specifically require a client-side Javascript solution or is this just the way you have gone about it so far?
On the Server Side, placing a #PreDestroy annotation above a Backing Bean method causes that method to be invoked just before the Bean goes out of scope.
If you write a method which invalidates the session (session.invalidate()) with this annotation, it will be called when the user leaves your page without clicking Log Out.
Backing Bean:
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
#ManagedBean
#SessionScoped
public class PreDestroyBean {
//Called by button - log out perhaps?
public void killTheSessionDeliberately() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
session.invalidate();
}
#PreDestroy
public void revokeLicense() {
System.out.println("PreDestroy method was called.");
}
}
Page Button:
<h:form>
<p:commandButton id="killSession" value="Kill Session"
actionListener="#{preDestroyBean.killTheSessionDeliberately()}" update="#form" />
</h:form>

You can use p:remoteCommand along with onunload.
example:
<body onunload="test();">
<form id="exit">
<p:remoteCommand id="test" name="test" action="#{ContatoMB.teste}"/>
</form>
</body>
referencing http://forum.primefaces.org/viewtopic.php?f=3&t=15695
It works for me.

Related

UWP WebView control doesn't refresh when asked if page request method was POST

The UWP WebView control has a Refresh() method that works fine for most pages, but calling the method directly after the WebView has been navigated somewhere by POST (e.g. a form submission inside the WebView itself) raises the NavigationStarted event, but never actually performs any refresh.
Here's some minimised XAML that demonstrates the issue:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Name="Refresh" Click="Refresh_Click" Content="Refresh" />
<WebView Grid.Row="1" Name="BrowserView" />
</Grid>
</Page>
Here's the relevant code-behind:
namespace App1
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
BrowserView.NavigationCompleted += BrowserView_NavigationCompleted;
BrowserView.NavigationStarting += BrowserView_NavigationStarting;
BrowserView.Navigate(new Uri("http://localhost/test.php"));
}
private void Refresh_Click(object sender, RoutedEventArgs e)
{
BrowserView.Refresh();
}
private void BrowserView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
// Always called on first load and when refreshed (even for POST results)
Debug.WriteLine($"Navigation starting for URI {args.Uri}");
}
private void BrowserView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
// Not called when a POST result is being refreshed
Debug.WriteLine($"Navigation completed");
}
}
}
As a test, I've created and hosted a very small PHP page with the following content and hosted it at http://localhost/test.php:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<form method="POST">
<p>Page loaded at <?php echo date('H:i:s') . (!empty($_POST['in']) ? ' with text "'.htmlspecialchars($_POST['in']).'"' : '') ?></p>
<input type="text" name="in" />
<input type="submit" />
</form>
</body>
</html>
Once I point my WebView at this page I can refresh the page on the initial load just fine, but after submitting the form, Refresh() raises the NavigationStarting event but does not navigate the page at all (as indicated by the timestamp on the test PHP result not changing) and never raises a corresponding NavigationCompleted event.
When the same page is visited in Edge, the user is shown this warning when attempting to refresh a POST result:
Choosing Retry resubmits the POST data to the server, and choosing Cancel behaves similarly to what I'm seeing (doing nothing at all). This dialog is obviously not emulated in any way by the UWP WebView control.
Since my actual application shows users a refresh button, I need the button to do something regardless of whether or not they've recently submitted a form, or alternatively I need to disable the refresh button so it's not confusing to users when the button does nothing.
Right now the only solution I have (which astonishingly seems to work, but is really nasty) is to call GoBack(), then in the NavigationCompleted event handler immediately call GoForward().
I could settle for an option that allows me to detect this condition (something like WebView.CanRefresh so that I could disable my Refresh button), or worst case scenario some kind of result/exception that allows me to communicate to the user what has (not) happened and why.
If I understand your question correctly, you want to refresh the page after form has been submitted.
If so, you could check if the form has been submitted in php handler. Please check this thread: Checking if form has been submitted - PHP. Then, in the php handler, you could call the javascript method to refresh the page like window.location.reload().

How to disable and enable a command button on click of another command button?

I have 2 command buttons as shown,
<h:commandButton action="#{beanOne.getRefreshData}"
image="images/refresh_data.png" alt="#{messages.refresh}"
style="margin-top:8px" />
<h:commandButton action="#{beanTwo.resetFilter}" id="resetFilterBtn"
disabled="#{beanOne.disabledBtn}"
image="images/reset-filter.png" alt="#{messages.reset_filter}"
style="margin-top:8px;margin-left:5px" />
where refresh data functionality which needs to be invoked in the Application Logic Phase is as such,
public String getRefreshData() throws Exception {
try {
LOG.debug("In class OneBean : getRefreshData()");
setDisabledBtn(true);
// Some business logic code goes here
} catch (Exception e) {
throw e;
}
finally{
}
return IConstants.SUCCESS;
}
The RESET FILTER button needs to be disabled as soon as user clicks on REFRESH DATA and after the refresh data functionality has been processed in the backing bean, only then it(RESET FILTER) needs to be enabled.
Any suggestions?
So, you want to disable it before the request is sent. Your current attempt only disables it after the response associated with the request is returned. This is indeed too late.
Throw some JavaScript into the game to achieve that.
<h:commandButton ... onclick="document.getElementById('form:resetFilterBtn').disabled=true" />
<h:commandButton id="resetFilterBtn" ... />
It will "automagically" be re-enabled when the page refreshes as response to the form submit request. In case you're actually using ajax, then make sure that the disabled button is covered by ajax update.
Update
As per comments, I just used this form and bean on a further blank project with most minimal configuration (and only one dummy image file).
<h:form id="form">
<h:commandButton id="one" image="test.png" action="#{bean.sleep}"
onclick="document.getElementById('form:other').disabled=true" />
<h:commandButton id="other" image="test.png" action="#{bean.sleep}" />
</h:form>
#ManagedBean
#RequestScoped
public class Bean {
public void sleep() throws Exception {
Thread.sleep(2000);
}
}
To be sure, I also added this CSS to the test page because it was in Firefox not immediately visually visible if the button was disabled (although it was visible in the DOM inspector):
<style>input[disabled] { border: 5px solid red; }</style>
It also works properly.

Redirect using <p:commandButton>

Following line should save a new item and redirect to another page. So far, it saves correctly, but it doesn´t redirect. No errors or warnings.
<p:commandButton id="savebutton" ajax="false" value="#{msg['addCategory.save']}" actionListener="#{addCategoryController.doSave()}" />
Code behind:
public String doSave(){
categoryAddEvent.fire(categoryProducer.getSelectedCategory());
return Pages.LIST_CATEGORIES;
}
As I said, the first line executes correctly, the second one doesn´t seem to do anything. Any ideas what I could be doing wrong?
You can do it in two ways:
Navigation:
Calling an action, with the commandButton component set as ajax false, and the bean method returning a String (as you already have).
xhtml page:
<p:commandButton id="savebutton" ajax="false" value="#{msg['addCategory.save']}" action="#{addCategoryController.doSave()}" />
Redirect:
Calling an actionListener, with the commandButton component set as ajax true, with the bean method not returning value, but instead performing itself the redirection to the desired page.
xhtml page:
<p:commandButton id="savebutton" ajax="true" value="#{msg['addCategory.save']}" actionListener="#{addCategoryController.doSave()}" />
java bean:
public void doSave(){
categoryAddEvent.fire(categoryProducer.getSelectedCategory());
FacesContext.getCurrentInstance().getExternalContext().redirect(Pages.LIST_CATEGORIES);
}

Event 'onsave' in rich:editor doesn't fire

I'm implementing some kind of frontend editor in my web page, using rich:editor. When clicking a link, the editor should open, and after saving editor's content, the editor should close again. I'm having trouble with onsave event for closing the editor. Here is my code.
This is the link that opens the editor, due to setting the property bean.show to true. It works ok:
<h:commandLink>
...
<f:setPropertyActionListener value="true" target="#{bean.show}" />
</h:commandLink>
This is the editor itself, only rendered when show evaluates to true:
<h:form>
<rich:editor value="..." onsave="showEditor(false)" rendered="#{bean.show}" />
</h:form>
The onsave event should close the editor by setting the show property to false again, but the editor stays open, because showEditor() is not called:
<a4j:jsFunction name="showEditor">
<a4j:param name="param1" assignTo="#{bean.show}" />
</a4j:jsFunction>
Am I doing something completely wrong? Or do you have any other ideas how to realize this? Any help is appreciated.
just double-checked: in version richfaces 4.x, there is no onsave attribute at all, but
oninit
onblur
onfocus
ondirty
onchange
like pointed out in the org.richfaces.component.UIEditor class. The same is true, if you want to use f:ajax to ajaxify the editor.
Right now, the "save"-icon in the editor just sends a form.submit() or something. So either try to add your jsFunction on that event or to introduce an own save-button.
Edit: Richfaces 4 uses the javascript based CKEditor, so if you want to overwrite their "save"-button, this forum entry regarding CKEditor's save implementation might be of your help.
Also a valueChangeListener might be a possibility solution to trigger your Bean.setShow(boolean show) property.
xhtml:
<rich:editor value="#{bean.editorValue}"
valueChangeListener="#{bean.valueChanged}" />
method in managed bean:
public void valueChanged(ValueChangeEvent e) {
// do the code to close the window here
}
The valueChangeListener also works in Richfaces 4.3, but maybe starting within the javascript of the CKEditor is the better choice.
Hope, that helps... L.

Primefaces Captcha Component not working

I am using PF3.5+JSF2.1.22 and in my web application i am using Primefaces Captcha component. I am getting some weird issue in capcha component,i used captcha component like this in application
<p:captcha id="captcha" label="Captcha" theme="white" />
And i have a PF command page to submit the values to bean
<p:commandButton id="clear" value="Clear" update="captcha" styleClass="kuberbutton" />
When i am using button like above after form submit if any validation issue and other issue coming and age is loading again then Captcha is not visible in page any more but when i am using ajax="false" in PF button then it is working,is this is behavior this component will work i have to do ajax="false"? I checked the PF website they also did same thing Primefaces Captcha
Captcha component in Primefaces currently does not support ajax behavior , that why you must use ajax="false" in your <p:commandButton , you page must be fully reloaded for the captcha to work properly...
If you must have the ajax behavior you could use some other third party solution...
Haven't tried the following, but it might help with ajax issues:
recaptcha - AJAX AP
Displaying reCAPTCHA Without Plugins
How can I load a reCaptcha form using jQuery/AJAX while leaving the reCaptcha scripts in place?
As already said Primefaces Captcha component can't be updated by ajax request. But there is a simple solution - update everything but not Captcha component itself.
Your XHTML:
<h:form id="myForm">
<h:panelGroup id="updateFormAllValuesButNotCaptcha">
Name: <p:inputText id="name" value="#{captchaBean.name}" required="true"/>
<br/>
Comment: <p:inputTextarea id="comment" value="#{captchaBean.comment}" required="true"/>
<br/>
</h:panelGroup>
<p:captcha/>
<p:commandButton value="click me" update="updateFormAllValuesButNotCaptcha"
actionListener="#{captchaBean.someAction}" oncomplete="Recaptcha.reload()"
onerror="Recaptcha.reload()"/>
</h:form>
<p:messages globalOnly="false" autoUpdate="true"/>
Your backing bean:
#ManagedBean
#ViewScoped
public class CaptchaBean implements Serializable {
private String name;
private String comment;
public String getComment() { return comment; }
public void setComment(String comment) { this.comment = comment; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void someAction() {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Done", "");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
Note that I am updating updateFormAllValuesButNotCaptcha panel which contains all form input fields but not Captcha itself. It is also important to notice that Captcha can't be reused, so you have to reload it always when ajax request has been completed or ended with error.
What you update after commandButton's action succeeded is up to you. You can hide form (do not render it) and show only confirmation message to make sure user won't try to send comment again.

Resources