I have dashboard with panels:
<p:dashboard id="board" model="#{dashboardOptionsMB.model}">
<c:forEach var="item" items="#{dashboardOptionsMB.emsWidgets}">
<ui:include src="/pages/dashboard/panel.xhtml">
<ui:param name="widget" value="#{item.webDashboardDbBean}" />
<ui:param name="emsValue" value="#{item.emsValue}" />
</ui:include>
</c:forEach>
</p:dashboard>
I load a list dashboardOptionsMB.emsWidgets with content before rendering page, and this works fine with panel component:
panel.xhtml:
<p:panel id="#{widget.widgetid}" header="#{widget.widgetheader}" closable="true" >
<h:outputText value="#{emsValue.value}" />
...
</panel>
So, before each rendering I initialize the list with all elements and content with this method:
DashboardOptionsMB:
private void initWidgets(WebDashboardsDbBean dashboard) {
//dashboard is JPA entity from database
emsWidgets = dashboard.getWidgets();
...
}
What I want to achieve is to load each panel content dynamically after page load. For example each panel should call:
initWidget(String widgetId)
after page load, and when this method is completed to update its content.
Use p:remoteCommand to create some Ajaxified Javascript which will be executed when body is loaded:
<h:body onload="loadWidgets()">
<!-- content -->
<p:remoteCommand name="loadWidgets"
update="#{widget.widgetid}"
actionListener="#{dashboardOptionsMB.initWidgets}"/>
</h:body>
Alternatively, you might use the autoRun="true" argument to have it executed when document is ready:
<p:remoteCommand name="loadWidgets"
update="#{widget.widgetid}"
actionListener="#{dashboardOptionsMB.initWidgets}"
autoRun="true"/>
See also:
JSF lazy loading component value
Make your Primefaces app load faster with lazy loading
Related
I am trying to implement a dynamic rendering on a JSF composite component (I'm using Primefaces). Basically, I figured that many rendering component are like "header + content" based. I would like to make a generic implementation in which the developer doesn't have to care about how the rendering is done (and the rendering could be configurable via another bean in the app. That is, something like :
The main component (accordion / tabview / grid, etc)
<composite:implementation>
<p:accordionPanel rendered="#{composite.attrs.renderingType eq 'accord'}>
<composite:insertChildren/>
</p:accordionPanel>
<p:tabView rendered="#{composite.attrs.renderingType eq 'accord'}>
<composite:insertChildren>
<f:param name="renderingType" value="accord"/>
</composite:insertChildren>
</p:tabView>
<c:if test="#{composite.attrs.renderingType eq null}">
<composite:insertChildren>
<f:param name="renderingType" value="tabView"/>
</composite:insertChildren>
</c:if>
</composite:implementation>
The "item" component (a accordion tab, a tabview tab, a simple grid, etc)
<composite:implementation>
<p:tab rendered="${renderingType eq 'accord'}">
<composite:insertChildren/>
</p:accordionPanel>
<p:tabView rendered="${renderingType eq 'tabView'}">
<composite:insertChildren/>
</p:tabView>
//....etc.
</composite:implementation>
The call for those composite components would be :
<appcc:myCustomRenderer renderingType='How I want to render it'>
<appcc:myCustomRendererItem header="Title1">
//Content 1
</appcc:myCustomRendererItem>
<appcc:myCustomRendererItem header="Title2">
//Content 2
</appcc:myCustomRendererItem>
//Etc.
</appcc:myCustomRenderer>
At the moment I didn't think about facets (should I ?) for this implementation. in a simple case (the main component renders only an accordion panel, and the item component renders only one tab), it doesn't seem to work. ANy idea why ?
//Main component
<composite:implementation>
<p:accordionPanel>
<composite:insertChildren/>
</p:accordionPanel>
</composite:implementation>
//Item Component
<composite:implementation>
<p:tab >
Any content
</p:tab>
</composite:implementation>
Thank you!
I have a JSF 2 application that has two pages, one to list students and one to show details of a given student. The listing page has a link to the details page in each row of the students table, that opens a new tab in browser to show those details, when clicked.
Now the requirements changed to no more show details in a new tab, but in a modal dialog in the listing page.
My idea is to simply embed the details page content in the modal dialog so the listing page will not get too big and hard to maintain. Here start my doubts. After some research I changed the link in each row of the listing to the following button:
<p:commandButton value="Details" type="button"
onclick="PF('dialog-details').show()">
</p:commandButton>
The dialog is declared as follows:
<p:dialog widgetVar="dialog-details" header="Details" modal="true" width="95%">
<ui:include src="student_details.xhtml">
<ui:param name="id" value="#{student.id}"/>
</ui:include>
</p:dialog>
Finally, the details page was changed to be something like this:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:viewParam name="id" value="#{studentBean.id}" />
</f:metadata>
<h1 class="title ui-widget-header ui-corner-all">Details of #{studentBean.bean.name} / #{studentBean.bean.number}</h1>
</ui:composition>
When I click the button, the dialog really shows and the content is the details page. I see the following content in the dialog:
Details of /
No errors at all, but the data that should be shown, isn't. A breakpoint was set in StudentBean.setId() (this method loads a property named bean with the Student instance corresponding to the passed id) but it is never hit.
After some time thinking about it, I came to understand why it does not work. The parameter passed to the details page is student.id, but student is the name used as the var in the <p:datatable/> that show all the students, so student is not valid in <p:dialog/> which is outside the <p:datatable/>.
So, what I need is a way to show the dialog using the id of the corresponding student in a given row. Ideally, I would like an ajax call here, so the details would loaded only when neded.
Any ideas?
The button should be an ajax button which sets the currently iterated entity in the bean, and then updates the dialog's content, and finally shows it. The dialog should just reference that entity in the bean and update the list and table on save. It's very important that dialog is placed outside the main form and that it has its own form.
Here's a kickoff example:
<h:form id="master">
<p:dataTable value="#{bean.entities}" var="entity">
<p:column>#{entity.property1}</p:column>
<p:column>#{entity.property2}</p:column>
<p:column>#{entity.property3}</p:column>
...
<p:column>
<p:commandButton value="View" action="#{bean.setEntity(entity)}"
update=":detail" oncomplete="PF('detail').show()" />
</p:column>
</p:dataTable>
</h:form>
<p:dialog id="detail" widgetVar="detail">
<h:form>
<p:inputText value="#{bean.entity.property1}" />
<p:inputText value="#{bean.entity.property2}" />
<p:inputText value="#{bean.entity.property3}" />
...
<p:button value="Close" onclick="PF('detail').hide(); return false" />
<p:commandButton value="Save" action="#{bean.save}"
update=":master" oncomplete="if(!args.validationFailed) PF('detail').hide()" />
</h:form>
</p:dialog>
With this inside a #ViewScoped bean:
private List<Entity> entities; // +getter
private Entity entity; // +getter+setter
#EJB
private EntityService entityService;
#PostConstruct
public void load() {
entities = entityService.list();
entity = null;
}
public void save() {
entityService.save(entity);
load();
}
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Creating master-detail table and dialog, how to reuse same dialog for create and edit
Keep p:dialog open when a validation error occurs after submit
Difference between rendered and visible attributes of <p:dialog>
How to display dialog only on complete of a successful form submit
Below is the code snippet:
tansaction.xhtml
<h:form id="form1">
<p:dataTable value="#{transactionMB.transactionEntryList}" var="transInfo" rowStyleClass="tdDownValue">
</p:dataTable>
</h:form>
<h:form id="form2">
<p:dataTable value="#{transactionMB.loggingList}" var="logInfo" rowStyleClass="tdDownValue">
</p:dataTable>
</h:form>
<h:form id="form3">
<p:dataTable value="#{transactionMB.salesEntryList}" var="salesInfo" rowStyleClass="tdDownValue">
</p:dataTable>
</h:form>
Please suggest.Thanks in advance.
The idea is to start long-running initialization of lists after the page load.
You can try something like:
Do not initialize your lists in bean constructor/post construct method. Instead of it, add to the bean public methods, that you will call after page load.
public void loadTransactionEntryList();
public void loadloggingList();
public void loadSalesEntryList();
Add loading indicators near the table, and remoteCommands to call load* methods. Note, that by default loading indicators are shown and tables are hidden. oncomplete call is used to toggle indicator and table after command finishes.
<h:form id="commands-form">
<p:remoteCommand name="loadTransactionEntryListCommand" action="#{transactionMB.loadTransactionEntryList}"
update=":form1" oncomplete="hideLoadingDisplayTable('#form1');"/>
<p:remoteCommand name="loadloggingListCommand" action="#{transactionMB.loadloggingList}"
update=":form2" oncomplete="hideLoadingDisplayTable('#form2');"/>
<p:remoteCommand name="loadSalesEntryListCommand" action="#{transactionMB.loadSalesEntryList}"
update=":form3" oncomplete="hideLoadingDisplayTable('#form3');"/>
</h:form>
<h:form id="form1">
<div class="loading-indicator" style="display: block;">...</div>
<p:dataTable value="#{transactionMB.transactionEntryList}" var="transInfo" rowStyleClass="tdDownValue" style="display: none;">
</p:dataTable>
</h:form>
<h:form id="form2">
<div class="loading-indicator" style="display: block;">...</div>
<p:dataTable value="#{transactionMB.loggingList}" var="logInfo" rowStyleClass="tdDownValue" style="display: none;">
</p:dataTable>
</h:form>
<h:form id="form3">
<div class="loading-indicator" style="display: block;">...</div>
<p:dataTable value="#{transactionMB.salesEntryList}" var="salesInfo" rowStyleClass="tdDownValue" style="display: none;">
</p:dataTable>
</h:form>
Call commands with JavaScript in the end of the document or with jquery's (document ).ready().
<script type="text/javascript">
loadTransactionEntryListCommand();
loadloggingListCommand();
loadSalesEntryListCommand();
</script>
Finally, implement hideLoadingDisplayTable(formId) function to hide loading indicator and show table with JavaScript.
Why don't you use pagination with lazy loading in your data tables. Only first page of data will be loaded when your XHTML page is loaded, which should certainly reduce your load time.
Extend LazyDataModel and implement load(...) methods to lazy load your data in tables.
Initiate your database connections, and create your custom lazyDataModel objects in a method of your backing bean which is annotated with #postConstruct. Maintain current page and page size in your lazyDatalModel. In load(...) method get the next page from the database and return.
These are few links to help you.
Primefaces datatable paginationand lazy loading, see primefaces showcase -
http://www.primefaces.org/showcase/ui/data/datatable/lazy.xhtml
JDBC pagination -
http://java.avdiel.com/Tutorials/JDBCPaging.html
If you are using Persistance (JPA or Hibernate ), see for setFirstResult() and setMaxResult() methods of Query object.
Setup:
I have 2 forms A & B
I have a commandLink in form A:
<h:commandLink actionListener="#{homeView.selectDiv('homeUpdates')}">#{msg.homeUpdates}
<f:ajax render=":B" execute="#this" />
</h:commandLink>
...which updates form B.
The problem is that when I click the ajax link, it rebuilds form A as well and gets an exception from a ui:repeat I have. Is this correct behaviour? Should it rebuild form A as well?
I am using JSF 2.2 and form A contains a ui:fragment=>ui:include=>ui:repeat
=====Added SSCCE=======
The following code does not run after pressing Update B! twice. It gives an exception of duplicate id. The value for ui:repeat is irrelevant
<h:head>
</h:head>
<h:body>
<h:form id="A">
<ul class="tableView notification">
<ui:repeat var="notification" value="#{dashboardBean.notifications}">
<li>
xx
</li>
</ui:repeat>
</ul>
<h:commandLink value="Update B!" listener="#{dashboardBean.toggleRendered}">
<f:ajax execute="#this" render=":B" />
</h:commandLink>
</h:form>
<h:form id="B">
</h:form>
</h:body>
Upon initial request the view is created, upon postbacks the view is restored. To recite some points of JSF 2.2 specification for clarity (emphasis mine):
P. 2.2.1:
If the request is not a postback ... call createView() on the ViewHandler. If the request is a postback, ... call ViewHandler.restoreView(), passing the FacesContext instance for the current request and the view identifier, and returning a UIViewRoot for the restored view.
P. 2.5.8:
Selected components in a JSF view can be priocessed (known as partial processing) and selected components can be rendered to the client (known as partial rendering).
P. 13.4:
The JavaServer Faces lifecycle, can be viewed as consisting of an execute phase and a render phase. Partial traversal is the technique that can be used to “visit” one or more components in the view, potentially to have them pass through the “execute” and/or “render” phases of the request processing lifecycle.
When you use AJAX, PartialViewContext class will contain all the information that's needed to traverse the restored view.
So, to get back to your question, under <f:ajax render=":B" execute="#this" /> setup, only the form with id="B" will be rerendered, which implies <h:form id="B">, no form nestings, etc.
Regarding your 'doesn't work' comment the simple test case with a plain view scoped managed bean gave me the expected results:
<h:form id="A" >
<h:outputText value="#{twoFormsBean.a}"/>
<h:commandLink actionListener="#{twoFormsBean.actionA}">
Update B!
<f:ajax execute="#this" render=":B"/>
</h:commandLink>
</h:form>
<h:form id="B" >
<h:outputText value="#{twoFormsBean.b}"/>
<h:commandLink>
Update Both!
<f:ajax execute="#this" render=":A :B"/>
</h:commandLink>
</h:form>
with
#ManagedBean
#ViewScoped
public class TwoFormsBean implements Serializable {
private String a = "A";//getter
private String b = "B";//getter
public void actionA(ActionEvent ae) {
a = "newA";
b = "newB";
}
}
I've created an ui:component to use like a popup, so I can create a lot of popups using the standard of this template.
The component is just a popup with two buttons (cancel and submit) and a content that can be overriden, like you can see here:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui">
<ui:component>
<p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
draggable="#{popup.modal}"
rendered="#{popup.visivel}" visible="#{popup.visivel}"
closeOnEscape="false" closable="false" header="#{titulo}"
resizable="false" styleClass="autoWidthDialog" showEffect="fade"
hideEffect="fade">
<h:panelGroup style="width:100%">
<p:focus />
<ui:insert name="conteudo">Nenhum conteúdo definido!</ui:insert>
<h:panelGrid id="#{idPopup}PainelMensagens" style="width:100%">
<p:messages />
</h:panelGrid>
<ui:insert name="barraDeBotoes">
<h:panelGroup layout="block" style="width:100%">
<p:commandButton value="CANCELAR" immediate="true" update="#form"
style="float:right" action="#{controladorPopup.fechar}"
onclick="#{idPopup}.hide();" />
<p:commandButton value="OK" style="float:right"
update="#form formAlerta"
action="#{controladorPopup.submit}"
process="#form" />
</h:panelGroup>
</ui:insert>
</h:panelGroup>
</p:dialog>
</ui:component>
</html>
The problem happen when I try to submit the form without filling the required fields. The correct behavior is just show again the popup with messages, but the dialog is rendered twice, one with the messages and one without the messages.
You can see this behavior here:
this is one use of this template:
<ui:composition template="../templates/popupSubmit.xhtml">
<ui:param name="titulo" value="Buscar pessoa" />
<ui:param name="popup" value="#{modeloPopupBuscaPessoa}" />
<ui:param name="controladorPopup"
value="#{controladorPopupBuscaPessoa}" />
<ui:define name="conteudo">
<h:panelGroup>
<h:panelGrid columns="2">
<h:outputLabel value="Tipo de cadastro:" style="float:none" />
<h:selectOneMenu value="#{controladorSugestaoPessoa.tipoCadastro}"
immediate="true">
<f:selectItems value="#{carregadorTipoCadastro.itens}" />
<f:ajax event="change" immediate="true" />
</h:selectOneMenu>
</h:panelGrid>
<h:outputText value="Buscar por:" />
<h:selectOneRadio value="#{controladorSugestaoPessoa.tipoBusca}"
immediate="true">
<f:selectItems value="#{carregadorTipoBuscaPessoa.itens}" />
<f:ajax event="change" immediate="true" />
</h:selectOneRadio>
<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
forceSelection="true" maxResults="10" queryDelay="500"
completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa}"
converter="#{conversorSelectItem}" />
</h:panelGroup>
</ui:define>
</ui:composition>
And these are some use:
<h:form id="cadastroPessoa">
<ui:include
src="resources/components/popups/modulo_cadastro/popupNovoCadastroPessoa.xhtml">
<ui:param name="idPopup" value="popupNovoCadastroPessoa" />
</ui:include>
<ui:include
src="resources/components/popups/modulo_cadastro/popupCadastroPessoa.xhtml">
<ui:param name="idPopup" value="popupEdicaoCadastroPessoa" />
</ui:include>
<ui:include
src="resources/components/popups/modulo_cadastro/popupBuscaPessoa.xhtml">
<ui:param name="idPopup" value="popupBuscaCadastroPessoa" />
</ui:include>
</h:form>
<h:form id="cadastroProduto">
<ui:include
src="resources/components/popups/modulo_cadastro/popupCadastroProduto.xhtml">
<ui:param name="idPopup" value="popupNovoCadastroProduto" />
</ui:include>
</h:form>
Could someone tell me why this is happening??
I've posted the same question in primefaces forum (like Tommy Chan told), and someone answered this:
You are probably placing your dialog in the form you are updating which is a nono. Never update the dialog only the stuff in the dialog
I've tried to do this until I saw all my dialogs have "rendered" attribute coming from server (just see the first xml), I have a lot of dialogs in this application and some of them have relation with others (on server), these last are on the same form.
I did something different, I only created this javascript code:
function removerDialogo(id) {
setTimeout(function() {
removerDialogoAposIntervalo(id);
}, 100);
}
function removerDialogoAposIntervalo(id) {
id = id.replace(':', '\\:');
jQuery('div.ui-dialog')
.find('#' + id)
.parent().eq(1)
.remove();
}
and called this on dialog "onShow" attribute:
<p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
draggable="#{popup.modal}" rendered="#{popup.visivel}"
visible="#{popup.visivel}" closeOnEscape="false" closable="false"
header="#{titulo}" resizable="false" styleClass="autoWidthDialog"
showEffect="fade" hideEffect="fade" onShow="removerDialogo(this.id)">
I don't like to do things like this, but I can't find a better way to solve this...
If someone give me a better solution, I will be grateful
In my case I cannot user oncompleteI) method to hide the dialog because it has to be closed to some business logic.
I my case I have use primefaces tabs on UI. Every time I navigate the tabs and then click on button on which dialog appears then my dialogs number are increasing proportionality
So I have used simple jquery script to remove all the duplication dialog from the UI
e UI.
function removeDuplicateDialogs(dialogId) {
\\ generally all our components have : character we have to
\\ replace ':' with '\\:'(applying escape character)
dialogId = dialogId.replace(/\:/g, '\\:');
var dialogs = jQuery("div[id=" + dialogId + "]");
var numOfDialogs = dialogs.length;
numOfDialogs = numOfDialogs - 1;
for (var i = 0; i < numOfDialogs; i++) {
jQuery(dialogs[i]).remove();
}
}
As i said on the primefaces forum, you are updating your forms with the dialog in it... you need to place your dialogs out of your form and update them seperatly. If you need to use a form in your dialog then place it in you dialog:
<p:dialog><p:form> </p:form> </p:dialog>
I had the same problem with a dialog, the solution was place in the update of the commandButton that show the dialog component the specific id of the Dialog Component not the form id, the solution looks like this:
<p:dialog id="dialogId">
<p:commandButton value="OK" style="float:right"
update="#form dialogId"
action="#{controladorPopup.submit}"
process="#form"/>
</p:dialog>
I would check that your widgetVar="#{idPopup}" id="#{idPopup}" is the same before you submit and after you submit the form. Maybe it has changed and primefaces thinks it doesn't exist anymore and creates a new one.
Add the oncomplete attribute to your submit button and let it hide the dialog:
<p:commandButton value="OK" style="float:right"
update="#form formAlerta"
action="#{controladorPopup.submit}"
process="#form"
oncomplete="#{idPopup}.hide();"/>
putting the forms inside dialog isnt the best way to solve it, if you access your application with IExplorer, dialogs wont work with this approach
This is an awful bug with no official answer...
I'm using a dialog to render a Google map. The way I handle the bug (using JQuery) is by counting the number of ".map" elements in the DOM on primefaces:dialog.onShow... I then select the :last .map instance rendered (or in your case, whatever content class you're working with), and .remove() the dialog which contains it:
Markup (approx):
<pri:dialog onShow="popupOpen();" etc...>
<div id="map" class"map"></div>
</pri:dialog>
JavaScript:
function onShowDialog(){
if($(".map").length > 1){
$cull = $(".map:last");
$cull.closest(".ui-dialog").remove();
}
}
If you're a sadist you could, quite comfortably, make that a one liner... I see this as a Primefaces bug. The close button should outright destroy the dialog.