Primefaces how to toggle a dashboard widget/panel visibility using ajax? - ajax

I have a dashboard with a considerable number of widgets / panels which are working just fine.
I'm looking for a way to toggle the visibility of a specific one using a commandButton ction listener without having to refresh the page, i.e. via AJAX.
<p:dashboard id="board" model="#{dashboardBean.model}">
<!-- iteration code begins -->
<p:panel id="#{wdgt.code}" header="#{wdgt.title}">
<h:outputText value="One of the dozens of widgets" />
</p:panel>
<!-- iteration code ends -->
<p:panel id="staticWdgtId" header="Static Widget Initially Invisible" visible="false">
Some static content
</p:panel>
</p:dashboard>
Then in the backing bean, at some point this action needs to be fired via a commandButton or an actionListener...
public void showTheWidget() {
DashboardColumn dbc = this.model.getColumn(1);
dbc.getWidget(2); // does not get a widget object with a visibility attribute :((
// so that I could manipulate such as dbc.getWidget(2).setVisible(true);
}
Any ideas?

STATIC APPROACH
You can associate the panel with a boolean.
Panel
<p:panel id="staticWdgtId" header="Static Widget Initially Invisible"
visible="#{bean.panelShow}">
Some static content
</p:panel>
Button
<p:commandButton actionListener="#{bean.actionListener()}"
value="Button"
update=":staticWdgtId" />
Bean
public void actionListener() {
setShowPanel(true);
}
DYNAMIC APPROACH
Render all the panel with display: none
Dashboard
<p:dashboard id="board" model="#{dashboardBean.model}">
<p:panel id="#{wdgt.code}" header="#{wdgt.title}" style="display: none">
<h:outputText value="One of the dozens of widgets" />
</p:panel>
</p:dashboard>
remoteCommand
<p:remoteCommand name="panelsToShow"
actionListener="#{bean.panelsToShowAction()}"
oncomplete="handleComplete(xhr, status, args)" />
bean.panelsToShowAction() you need Gson
public void panelsToShowAction() {
List<String> panels = new ArrayList<String>();
//iterate over the panels you want to show, and put #{wdgt.code} which is the id of the panel
panels.add("Code1");//id
panels.add("Code2");//id
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("panels", new Gson().toJson(panels));
}
JS
$(document).ready(function() {
panelsToShow();
})
function handleComplete(xhr, status, args) {
var panels = eval('(' + args.panels + ')');
for (var i = 0, len = panels.length; i < len; i++) {
$('#'+panels[i]).show();
}
}

Related

How can I use ajax to submit h:selectOneRadio?

I'm having a problem getting things to work the way I think they should. I have a dataTable that I'm building from a list of benefits objects. Each of those objects can have one and only one type: group, account, or parent. I want to refresh the list when a radio button is selected. When the page loads, the group objects are displayed and the group radio button is pre-selected. If the user clicks the account radio button, I'm using Ajax to refresh the list, this time presenting Account objects. Here's the stripped down code:
XHTML:
<!-- Radio button to subset records -->
<h:selectOneRadio
id="varButtons"
value="#{benefitUI.buttonValue}"
styleClass="radio">
<f:selectItem
itemLabel="Group"
itemValue="G" />
<f:selectItem
itemLabel="Account"
itemValue="A" />
<f:selectItem
itemLabel="Parent"
itemValue="P" />
<p:ajax event="click" update="benList" process="#this" />
</h:selectOneRadio>
<p:dataTable
id="benList"
var="ben"
value="#{benefitUI.filteredBenefitList}"
rowIndexVar="vbRowIndex"
rowClasses="panel-grid-row-odd, panel-grid-row-even"
styleClass="mimic-datatable"
<p:column headerText="From" style="text-align:center;">
<h:outputText value="#{ben.beginDate}"/>
</p:column>
<p:column headerText="To" style="text-align:center;">
<h:outputText value="#{ben.endDate}"/>
</p:column>
</p:dataTable>
Java for BenefitUI:
#PostConstruct
public void init() {
/* Code that creates my unfiltered list removed for brevity. */
/** benefitList is the name of the unfiltered list **/
// Pre-select group on page load
setButtonValue("G");
}
public List<Benefit> getFilteredBenefitList() {
String filter = getButtonValue();
List<Benefit> filteredList = new ArrayList<Benefit>();
for (Benefit vb : benefitList) {
// The below code is working just fine, when filter is not blank
if ((filter.equals("G") & vb.getGroup() != null)
|| (filter.equals("A") & vb.getAccount() != null)
|| (filter.equals("P") & vb.getParent() != null)) {
filteredList.add(vb);
}
}
return filteredList;
}
public void setButtonValue(String bValue) {
this.buttonValue = bValue;
}
public String getButtonValue() {
return this.buttonValue();
}
The page loads just fine, displaying the group benefits. But when I click the Account button, an empty string is passed to the setButtonValue method, so when the filtered list is built, no records are included, and the page displays an empty list. What am I doing wrong that the itemValue isn't being sent to setButtonValue? Secondarily, why are the setButtonValue and the getFilteredBenefitList methods both being called four times?
I'm sure there's a keyword or something I'm missing, either on the Ajax line or in the selectItem, but I have no idea what it might be.

primefaces 4.0 p:graphicImage firefox bug

Here is my problem with firefox using primefaces 4.0 communication version: p:graphicImage
I have a list of model, whenever I click 1 item, I would like to get 1 image respectively
In xhtml file
<p:fieldset id="modelDiagramView" style="width:100%;height:1280px">
<p:panel id="panel">
<p:graphicImage value="#{modelBean.modelImage}" style="width: 100%;" cache="false"/>
</p:panel>
</p:fieldset>
in java bean, only session scope and application scope are running well
public StreamedContent getModelImage() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
System.out.println("render_response: id=" + modelID);
// So, we're rendering the HTML. Return a stub StreamedContent so
// that it will generate right URL.
// modelImage = new DefaultStreamedContent();
if (modelID != null)
getModelImage(modelID);
} else {
System.out.println("real reander: id=" + modelID);
if (modelID != null)
getModelImage(modelID);
}
return modelImage;
}
In chrome, when I click to item in list, the p:graphicImage will render a new image, however in firefox, only the first item's image will be render, if I want to display the next clicked item, I have to refresh browser(F5). Is it primefaces bug, how can I prevent that problem? Please help me
It's just a "bug" that browsers doesn't refresh a image with ajax if the URL will not be changed. Therefore you should add a random number to the resource url as below example.
xhtml
<p:graphicImage value="#{bean.stream}" id="pic" width="200">
<f:param name="randomNumber" value="#{beanxxx.randomNumber}"/>
</p:graphicImage>
beanxxx
public String getRandomNumber() {
Random r = new Random();
int low = 10;
int high = 100;
int result = r.nextInt(high-low) + low;
return Integer.toString(result);
}

Selection of extendedDataTable inside popupPanel not in Ajax Request Parameter

I am having a JSF page that contains a modal popupPanel from Richfaces and inside this popupPanel is an extendedDataTable. Now I want to have the user selection in my bean every time the user selects a new row. At first I want to show the code then I will explain the problem.
Part of the xhtml page with the popupPanel and the extendedDatatable:
<rich:popupPanel id="kontaktPanel" modal="true" onmaskclick="#{rich:component('kontaktPanel')}.hide()">
<rich:extendedDataTable
value="#{nachfrageBean.loadedKontakte}" var="kontakt"
selection="#{nachfrageBean.selection}" id="kontaktTable">
<rich:column>
<f:facet name="header">
<h:outputText value="#{messages['tabelle.kontakt.instknz']}" />
</f:facet>
<h:outputText value="#{kontakt.instKnz}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="#{messages['tabelle.kontakt.name']}" />
</f:facet>
<h:outputText value="#{kontakt.name}" />
</rich:column>
<a4j:ajax execute="kontaktTable kontaktPanel" event="selectionchange" listener="#{nachfrageBean.selectedRecord}" />
</rich:extendedDataTable>
</rich:popupPanel>
Corresponding bean with the listener and the needed members:
public class NachfrageBean {
private KontaktDTO kontakt;
private List<KontaktDTO> loadedKontakte = new ArrayList<KontaktDTO>();
/** DOCUMENT ME! */
private Collection<Object> selection;
public Collection<Object> getSelection() {
return selection;
}
public void setSelection( Collection<Object> selection ) {
this.selection = selection;
}
public List<KontaktDTO> getLoadedKontakte() {
//contacts are successfully loaded
return kontaktBusiness.getAllKontakte( );
}
public KontaktDTO getKontakt() {
return kontakt;
}
public void setKontakt( KontaktDTO kontakt ) {
this.kontakt = kontakt;
}
public void selectedRecord( AjaxBehaviorEvent event ) {
UIExtendedDataTable dataTable = ( UIExtendedDataTable )event.getComponent();
Object originalKey = dataTable.getRowKey();
for( Object selectionKey : selection ) {
dataTable.setRowKey( selectionKey );
if( dataTable.isRowAvailable() ) {
// do something with the selection
}
}
dataTable.setRowKey( originalKey );
}
}
The listener gets called successfully when the user selects a row in the datatable, but the selection is null, so I am getting a NPE. And when I remove the popupPanel and have my extendedDatatable directly in my page, then it works fine. I am always printing out the request parameters and I can see that there are two missing parameters when I have the datatable inside the pupupPanel. These request parameters are:
mainForm:kontaktTable:wi =
mainForm:kontaktTable:si = 3,3|3||x
So outside the popup the selection from the kontaktTable gets submitted but inside the popupPanel not. Does anyone know whats wrong here?
I just found a solution here .
By default the rich:popupPanel will be attached to the body and not to the form. Adding domElementAttachment="form" to the popupPanel just did it.

Primefaces : GraphicImage does not refresh

I waant to have abutton and a graphicimage. By default, the graphicimage is not displayed. If the user click on the button, the graphic image is displayed (rendered = true).
I can do it but I have to refresh the page to see the graphicimage displayed.
I think I have to use ajax component to make the displaying directly when the button is clicked but I don't manage to use it corectly. Could you guide me?
xhtml :
<h:body>
<h:form>
<p:commandButton value="Prendre la photo générique"
id="boutonPhotoGenerique" icon="ui-icon-image"
action="#{defaultCommandBean.affichePhotoGenerique}">
<p:graphicImage id="photoGenerique"
rendered="#{defaultCommandBean.rendered}"
value="photos/photo_generique.jpg" />
</p:commandButton>
</h:form>
</h:body>
Managed Bean :
#ManagedBean(name = "defaultCommandBean")
#SessionScoped
public class DefaultCommandBean {
private boolean rendered;
public boolean isRendered() {
return rendered;
}
public void setRendered(boolean rendered) {
this.rendered = rendered;
}
public void affichePhotoGenerique() {
rendered = true;
}
}
I found the problem : I surrounded my graphicImage component with a panel component, with id="panel" ; and modified my update attribute to update="panel" . Now, the picture is directy displayed.
Put the graphicImage outside the commandButton and in button declare
update = 'photoGenerique'. Like this:
<h:form>
<p:commandButton value="Prendre la photo générique" update="photoGenerique"
id="boutonPhotoGenerique" icon="ui-icon-image"
actionListener="#{defaultCommandBean.affichePhotoGenerique}">
</p:commandButton>
<p:graphicImage id="photoGenerique"
rendered="#{defaultCommandBean.rendered}"
value="photos/photo_generique.jpg" />
</h:form>

JSF 2 f:ajax lifecycle problem

The problem is, that if a property is changed during an f:ajax request and a binded panelGroup should be newly created depending on that changed value, the old value is used.
This code will explain the problem.
Here is the backingbean TestBean:
public String getFirst() {
return first;
}
public void setFirst(String first) {
this.first = first;
}
public String getLast() {
return last;
}
public void setLast(String last) {
this.last = last;
}
public String getName(){
return first+" "+last;
}
public void setDynamicPanel(HtmlPanelGroup panel){ }
public HtmlPanelGroup getDynamicPanel(){
Application app = FacesContext.getCurrentInstance().getApplication();
HtmlPanelGroup component = (HtmlPanelGroup)app.createComponent(HtmlPanelGroup.COMPONENT_TYPE);
HtmlOutputLabel label1 = (HtmlOutputLabel)app.createComponent(HtmlOutputLabel.COMPONENT_TYPE);
label1.setValue(" --> "+getFirst()+" "+getLast());
component.getChildren().add(label1);
return component;
}
and now the jsf/facelet code:
<h:form id="form">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{testBean.first}" />
<h:inputText id="last" value="#{testBean.last}" />
<h:commandButton value="Show">
<f:ajax execute="first last" render="name dyn" />
</h:commandButton>
</h:panelGrid>
<h:outputText id="name" value="#{testBean.name}" />
<h:panelGroup id="dyn" binding="#{testBean.dynamicPanel}" />
</h:form>
After the page was initially loaded the outputText and panelGroup shows both "null" as first and last. But after the button is pressed, the outputText is updated well, but the the panelgroup shows again only "null". This is due to the problem, that the "binded method" dynamicPanel is executed before the update of the first and last properties.
how can workaround this behaviour or what is wrong with my code?
If you add the attribute immediate="true" to your input elements, the values will be applied during the "Apply Request Values" phase, and hence be present before your action executes. You may or may not need the immediate attribute set to true on the commandButton as well.

Resources