Using PF 10, JSF 2.3
I try to open a url in a new tab when the user clicks on "Download report"
xhtml page:
<script type="text/javascript">
//<![CDATA[
function start() {
PF('statusDialog').show();
}
function stop() {
PF('statusDialog').hide();
}
//]]>
</script>
<h:form>
<p:menubar>
<p:menuitem value="Home" action="#{umigonBean.logout}" icon="pi pi-home"/>
<p:menuitem value="Download report" action="#{umigonBean.getReport}" onclick="PrimeFaces.monitorDownload(start);" icon="pi pi-arrow-down" oncomplete="PrimeFaces.monitorDownload(stop);"/>
</p:menubar>
</h:form>
Backing bean (session scoped, if this matters):
public void getReport(){
// report being generated in the form of a Google Slide...
// when it is generated, a redirect is made to the url of this Google Slide:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().redirect("http://docs.google.com/etc");
}
The solutions suggested by #BalusC for a commandButton are:
<h:form target="_blank">
(does not apply as my form contains different links, and only this one should open a new tab)
onclick="this.form.target='_blank'"
In my code above this would be:
onclick="this.form.target='_blank';PrimeFaces.monitorDownload(start);"
however when I choose this option, the action is not called (the "waiting" window appears and remains for ever).
This can be solved by the point 3 of the answer posted here:
public void submit() {
// ...
PrimeFaces.current().executeScript("window.open('myUrl');");
}
Related
I am using JSF for my webapp (combined with EJB) and Bootsfaces as JavaScript addition to show modal windows. I am having a list of items that are being shown through a dataTable. And by clicking on a command button inside my list I am opening a modal window, asking the user "wether he is sure he wants to delete". That modal confirm dialog has YES and NO. I can execute the yes execute button inside the modal window. But I cant do #{controller.delete(item)} because the item is only server side available while building the list table. Somehow I have to send the actual selected item to the modal window to set it somehow in that controller call...???
Anyone got an idea?
<!-- looping the jsf list //-->
<h:dataTable value="#{controller.itemlist}" var="item"...
...
<!-- showing modal window //-->
<h:commandButton value="delete" action="" onClick="return false;" p:toggle-data.... />
</h:dataTable>
</h:form>
...
<!-- modal window in panel, with item not set //-->
...
<h:commandButton action="#{controller.delete(item)}" />
</h:form>
</b:panel>
...
You could use ajax to populate your modal's content :
$.ajax({
url : "yourPage.jsf",
type : "POST",
data : {
id: "your object's id"
},
dataType : "html"
}).done(function(html) {
$("#yourModal").html(html);
});
This ajax should be called with onclick event on your <h:commandButton>
And of course, you'd need to create a JSF view for your modal content. This view will contain your text and your two buttons "Yes" and "No". "No" should just dismiss your modal, while "Yes" should call your bean action : <h:commandButton action="#{controller.delete(item)}" />.
Don't forget to populate your controller item with the id parameter to bind data to your view.
EDIT :
I'll try to show you an example.
Main View (view.xhtml) :
<h:form>
<h:dataTable value="#{controller.itemlist}" var="item">
<h:column>
...
</h:column>
<h:column>
<h:commandButton value="delete" onclick="return populateModal(#{item.id}); " />
</h:column>
</h:dataTable>
</h:form>
Script to populate your modal (view.xhtml) :
<script type="text/javascript">
function populateModal(id) {
$.ajax({
url: "view2.jsf",
type: "POST",
data: { id: id },
dataType: "html"
}).done(function(html) {
$("#modal").html(html);
$("#modal").show();
});
return false;
}
</script>
Then you need a view for your modal's content (view2.xhtml) :
<h:form>
Delete #{testBean2.item.name} ?
<h:commandButton value="YES" action="#{testBean2.delete(testBean2.item)}" />
<h:commandButton value="NO" onclick="return closeModal();" />
</h:form>
And a controller for this view (testBean2.java) :
private Item item;
#PostConstruct
public void init() {
// GET id parameter from HTTPRequest
// Populate Local Item
}
public void delete(Item item) {
// Delete your item
}
Using Primefaces I pass to a bean the id of the component that the user just clicked. I want the bean to change the style of this component. The relevant part of the bean:
public void passIdClicked() {
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
String idClicked = (String) map.get("idClicked");
UIComponent tile = FindComponent.doFind(context, idClicked);
Iterator<UIComponent> it = tile.getChildren().iterator();
UIComponent comp = it.next();
if (comp.getId().equals(idClicked)) {
HtmlOutputText labelDone = (HtmlOutputText) comp;
labelDone.setValue("heyyyyyyyyy");
labelDone.setStyleClass("myStyleClass");
}
}
The modifications are not appearing on screen. What am I missing?
[EDIT] UI Code:
(additional components get created in the "tiles" panelGroup dynamically in an initialization phase. The passIdClicked method modifies one of these components - the one clicked by the user.)
<h:head>
</h:head>
<h:body>
<h:form id="form">
<h:commandButton actionListener="#{bean.createNewTile()}" title="new" value="new"/>
<p:remoteCommand name="sendNameClicked" actionListener="#{bean.passIdClicked}"/>
</h:form>
<h:panelGroup layout="block" id="tiles">
</h:panelGroup>
<script type="text/javascript">
$(document).ready(function() {
$('.tile').click(function() {
sendNameClicked([{
name: 'idClicked',
value: $(this).attr('id')
}]);
});
});
</script>
</h:body>
#kocko answer is absolutely correct, but since you are using Primefaces you can also do it programmatically:
RequestContext.getCurrentInstance().update(comp.getClientId());
You will have to refresh the component(s), so that the styleClass change takes place.
You can, either:
Refresh the whole page.
For example:
<f:ajax render="#all" />
Or
Refresh a particular component:
For example:
<p:someComponent id="componentId">
....
</p:someComponent>
...
<f:ajax render="componentId" />
I am facing a problem with commandButton, it is working only when the type is submit. Can someone take a look and let me know if there is a solution for that? The code below is very simple and does have the the propose to illustrate what I need. The method test() is not executed. Method runSubmit is executed successfully.
I need that test method is executed without a submit as the original page does have validations that are executed during the submit, test() method must be executed without a submit as it is a preliminary operation before of the submit.
I am using PrimeFaces 4.0, JDK 7, Tomcat 6 and JSF 2.0 (Apache), however I think it is happening in Mojarra as well.
SESSION:
package com.andre.bean;
public class AndreBean {
public void runSubmit() {
System.out.println("Submit executed");
}
public String test() {
System.out.println("Not submit executed");
return "true";
}
}
XHTML
<html 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">
<h:head>
</h:head>
<h:form id="test">
<p:commandButton id="ns" value="not submit" type="button" action="#{andreBean.test}" ajax="false"></p:commandButton>
<p:commandButton id="s" value="submit" action="#{andreBean.runSubmit}"></p:commandButton>
</h:form>
</html>
Thank you very much
Andre
What's going on?
What you get is correct behaviour. In PrimeFaces button with type="button" works as it does in basic HTML - it doesn't cause any request. As PrimeFaces user's guide says:
Push buttons are used to execute custom javascript without causing an
ajax/non-ajax request. To create a push button set type as "button".
<p:commandButton type="button" value="Alert" onclick="alert('Prime')" />
If you want to "talk to" bean, you need to use type="submit" (which is default in p:commandButton).
However... contrary to submit buttons behaviour in HTML, in PrimeFaces such submission will not force redirection to new page but all communication will be handled by underlying AJAX requests.
Therefore only your second button will execute beans' method:
<p:commandButton id="s" value="submit" action="#{andreBean.runSubmit}" />
What probably you wanted to obtain?
If you don't want to send all your form to bean you can limit the scope of components that are processed with "process" attribute of p:commandButton:
<h:form id="test">
<p:inputText value="#{andreBean.value}"/>
<p:commandButton id="s" value="submit" action="#{andreBean.runSubmit}" process="#this" />
</h:form>
With the following bean you will see the difference:
public class AndreBean {
private String value;
public void runSubmit() {
System.out.println("Submit executed");
}
public String getValue() {
System.out.println("getValue");
return value;
}
public void setValue(String value) {
System.out.println("setValue: " + value);
this.value = value;
}
}
If you don't limit executed components in console you get:
getValue
setValue: foobar
Submit executed
...and with components limited only to process="#this" you get only:
Submit executed
Hope that helps.
Sometimes, the solution is simply add immediate="true", it changes the point, in JSF lifecyle, in which the bean action is triggered.
Here are an article about how and when use it:
immediate attribute article
Please check your binding with bean.
bean fields should be String or non primitive.
I am learning JSF 2 at the moment. One of the first things I want to realize is the following scenario:
I have a commandLink on my page. When this link is clicked, an h:panelGroup-Tag is rendered (depending on the boolean attribute in the corresponding ManagedBean - which is false by default). I want that panelGroup to not be rendered when the link which "opened" the panelGroup is clicked again (that already works) but I want the panelGroup also not to be rendered when the user clicks outside of that panelGroup (that doesn't work).
The ManagedBean looks like:
#ManagedBean
#SessionScoped
public class LocaleBean {
#PostConstruct
public void init(){
locale = new Locale("de_DE");
showLanguageDiv = false;
}
private boolean showLanguageDiv;
public boolean getShowLanguageDiv() {
return showLanguageDiv;
}
public void setShowLanguageDiv(final boolean showLanguageDiv) {
this.showLanguageDiv = showLanguageDiv;
}
public void switchShowDivStatus(ActionEvent e) {
showLanguageDiv = !showLanguageDiv;
}
The facelet looks like:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<div>
<h:commandLink style="float: right;padding: 2px" actionListener="#{localeBean.switchShowDivStatus}" value="#{msg.language}" >
</h:commandLink>
</div>
<h:panelGroup rendered="#{localeBean.showLanguageDiv}" style="clear:both;float:right;border:2px;border-style: solid" >
<p><h:commandButton .... /></p>
<p><h:commandButton .... /></p>
<p><h:commandButton .... /></p>
</h:panelGroup>
</h:form>
</ui:composition>
I already tried to add an hidden link which was clicked via javascript (when the user clicked anywhere in the body), which set the boolean attribute of the ManagedBean to false so that the panelGroup was not rendered. That worked partially because the panelGroup wasn't shown anymore. But on the other hand a click on the link to show the panelGroup had no effect anymore after doing that.
This is how it looked:
<h:body onclick="document.getElementById('invisibleform:invisiblelink').click()">
.
.
.
<h:form id="invisibleform">
<h:commandLink id="invisiblelink" actionListener="#{localeBean.switchShowDivStatus}"></h:commandLink>
</h:form>
</h:body>
So how can I resolve this issue? Is there a best practice of doing things like that? Was the hidden link the right approach? From what I've read so far it seems like this is something which should be done on client side via javascript. But all solutions I found were based on normal html-pages (non-JSF) and I can't image how this should be done when using JSF.
Thanks for any advice.
Are you able to use Primefaces along JSF? There is a Component <p:overlayPanel> See here for the showcase. Maybe that works for you...
<h:commandLink action="#{bean.action}" onclick="window.open('../note/note.faces', 'popupWindowName', 'dependent=yes, menubar=no, toolbar=no, height=450, width=700');">
In the above code popup is opened before action is completed when click the link.
is it possible to open after action is completed?
Just move the logic to be executed to the target page of the action.
First remove the onclick:
<h:commandLink action="#{bean.action}">
Then extend your Bean as follows:
private boolean executed;
public String action() {
executed = true;
return "targetpage";
}
public boolean isExecuted() {
return executed;
}
And finally display the JS code conditionally based on #{bean.executed}:
<h:panelGroup rendered="#{bean.executed}">
<script type="text/javascript">
window.open('../note/note.faces', 'popupWindowName', 'dependent=yes, menubar=no, toolbar=no, height=450, width=700');
</script>
</h:panelGroup>