How to create chrome like tabs with primefaces - jsf

There are buttons like chrome-firefox bookmarks(say "google","facebook","twitter"). What I want to do is when user clicks a button, its related tab will open. For example if user clicks google button, google tab will rendered.
I have created some tabs and binded these tab's "rendered" property. But the problem is when i close the tab, I couldn't change variable which binded to the tab's "rendered" property. For example when I open and close google tab and then click to openFacebookTab button, Google tab is also rendered with Facebook tab because renderGoogleTab still holds true.
Must I create tabs and tabview programmatically or is there an easy solution?
My view;
<p:commandButton value="openGoogleTab" actionListener="#{myController.openGoogle()}"/>
<p:commandButton value="openFacebookTab" actionListener="#{myController.openFacebook()}"/>
<p:tab id="googleId" closable="true" title="Google" rendered="#{myController.renderGoogleTab}"/>
<p:tab id="facebookId" closable="true" title="Facebook" rendered="#{myController.renderFacebookTab}"/>
My controller;
#Controller("myController")
#Scope("view")
public class MyController{
//some variables
openGoogle(){
renderGoogleTab = true;
}
openFacebook(){
renderFacebookTab = true;
}
//getter and setters
}

Try to modify your code as follow,
openGoogle(){
renderGoogleTab = true;
renderFacebookTab = false;
}
openFacebook(){
renderFacebookTab = true;
renderGoogleTab = false;
}

Not the best method probably, but one workaround is to place the tabs in two separate tabView components (as I understand you need to be able to open two tabs simultanously) and then add a tab close listener like in the showcase. Then in the listener set the corresponding render*Tab properties to false.
So the jspx would be somewhat like this:
<p:tabView>
<p:ajax event="tabClose" listener="#{myController.onGoogleClose}"/>
<p:tab id="googleId" closable="true" title="Google" rendered="#{myController.renderGoogleTab}"/>
</p:tabView>
<p:tabView>
<p:ajax event="tabClose" listener="#{myController.onFacebookClose}"/>
<p:tab id="facebookId" closable="true" title="Facebook" rendered="#{myController.renderFacebookTab}"/>
</p:tabView>
Another approach would be to add a client side listener which invokes a server side method when the user clicks the close button.

Related

How to stop Validation from firing when I open modal dialog with required fields on Primefaces

I cannot comprehend JSF lifecycle for this particular case.
I'm trying to develop a simple modal CRUD with Primefaces 6.0, and I'm having problems with the beheaviour of the add/edit modal.
What I'm trying to accomplish is:
Add
Click add button
Add/Edit dialog opens
InputText "field1" is disabled=false
Edit
Click edit button
Add/Edit dialog opens
InputText "field1" is disabled=true
So for this I linked "field1" disabled property to editMode variable on my bean.
When I click Add Button, linked action initAddRubro gets fired and sets editMode = false (let's say that by default is true).
The thing is when I click on Add button without immediate=true, validations gets fired for the Add/Edit modal window (Field1 is required=true).
If I use immediate=true on my Add Button then disabled property does not get refreshed.
Faces Bean
#Component
#Scope("session")
public class RubrosFacesBean implements Serializable{
private boolean editMode = true;
public String initAddRubro(){
editMode = false;
return null;
}
}
Page
<p:commandButton value="Add" icon="ui-icon-plusthick"
oncomplete="PF('addPanelDialog').show();" style="float: right"
immediate="true" ajax="true" action="#{rubrosFacesBean.initAddRubro}"/>
<p:dialog header="Rubro" widgetVar="addPanelDialog" height="200" style="margin-left: auto;" modal="true" id="addPanelDialog" >
<p:messages autoUpdate="true" />
<p:panelGrid columns="2" id="addPanel">
<h:outputLabel for="field1" value="Field 1: " />
<p:inputText id="field1" value="#{rubrosFacesBean.field1}" label="Field1" required="true" disabled="#{rubrosFacesBean.editMode}"/>
</p:panelGrid>
</p:dialog>
Any help is appreciated.
Thanks in advance.
Juan.-
You can keep immediate="true" on your Add Button and just add following attribute to it
update="addPanel"
or
you can set immediate="false" and add following attributes
process="#this" update="addPanel"
Whatever option you choose, after you press Add button validation will be skipped, Ajax will be executed and finally p:panelGrid will be updated refreshing disable property of p:inputText.
Do not forget to do the same with your Edit button.

primefaces command button not showing a confirm dialog until after the second click

So I'm pretty new to jsf, I want a confirm dialog to be shown only if an attribute is set to true in my backing bean. I have something like this.
I have a data table which is multi selectable. When you select items in the table, an attribute get sets in the backing bean to hold those items.
Basically what the "showDeleteDialog()" method does, is check to see if any of those items in the list is selected, only then will it show the confirm dialog if the delete button is selected.
So what I want to happen is once a person has selected items from the data table, click the delete button. Have a confirm dialog come up and then delete the selected items. If the user has no items selected from the data table. I want the delete button to not show the confirm dialog.
<p:commandButton
styleClass="referralTaskDeleteBtn"
id="deleteButton"
value="#{loc['RegionAdmin.TaskType.DeleteButton']}"
icon="ui-icon-close"
update="deleteConfirmDialog,#this"
rendered="true"
action="#{referralTasksController.showDeleteDialog()}"
oncomplete="if (#{referralTasksController.displayDeleteDialog}) { PF('confirmDailogWidget').show(); }"
style="visibility: #{referralTasksController.toggleDeleteAndCompleteButtons()};"
disabled="#{not referralTasksController.enableEditButtons()}"
>
</p:commandButton>
and the backing bean method
public void showDeleteDialog(){
if (selectedReferralTasks.size()!=0)
this.displayDeleteDialog = true;
}
Anytime I click this, my dialog box only opens after the second click. Any ideas why? I'll include the dialog in case that is needed. Any help would be appreciate.
<p:outputPanel id="confirmationDailogOutputPanel">
<p:confirmDialog
id="deleteConfirmDialog"
header="Confirm Delete"
message="Are you sure you want to delete the selected Tasks"
showEffect="fade" hideEffect="fade"
widgetVar="confirmDailogWidget"
>
<p:commandButton value="#{loc['RegionAdmin.TaskType.DeleteButton']}" styleClass="confirmDialogDeleteButton" icon="ui-icon-check"
action="#{referralTasksController.deleteTasks()}"
oncomplete="PF('confirmDailogWidget').hide();"
update=":#{p:component('NoticePanel')},referralsTaskList,completeButton,deleteButton"
/>
<p:commandButton value="#{loc['RegionAdmin.TaskType.CancelButton']}"
styleClass="confirmDialogCancelButton"
icon="ui-icon-close"
oncomplete="PF('confirmDailogWidget').hide();"/>
</p:confirmDialog>
</p:outputPanel>
Problem explanation
In this oncomplete="if (#{referralTasksController.displayDeleteDialog}) { PF('confirmDailogWidget').show(); }" part of code you mixed ExpressionLanguage (#{referralTasksController.displayDeleteDialog}) and JavaScript code (everything else).
So when you load page Expression Language is evaluated (you can put a breakpoint to check this). At the first time when page is loaded of course evaluation return false. The code looks like this oncomplete="if (false) { PF('confirmDailogWidget').show(); }". It will never call show() method.
When page is reloaded (after button click) Expression Language is once again evaluated. Now code looks like this oncomplete="if (true) { PF('confirmDailogWidget').show(); }" (if you select data in datatable of course). This is a reason why dialog shows on second attempt.
Solutions
First: Runtime update
Remove oncomplete="if (#{referralTasksController.displayDeleteDialog}) { PF('confirmDailogWidget').show(); }"
Change bean method to
public void showDeleteDialog(){
if (selectedReferralTasks.size()!=0){
RequestContext.getCurrentInstance().execute("confirmDailogWidget.show()");
}
}
}
More about this solution you can found in PF documentation Misc > Request Context or in Open from bean by RequestContext#execute()
Second: Use p:confirmDialog rendered parameter
Remove oncomplete="if (#{referralTasksController.displayDeleteDialog}) { PF('confirmDailogWidget').show(); }"
Add rendered parameter to p:confirmDialog like this <p:confirmDialog rendered="#{referralTasksController.displayDeleteDialog}". Take a look at PF documentation and list of p:confirmDialog attributes
Change update parameter after button click to update confirmationDailogOutputPanel like this <p:commandButton update="confirmationDailogOutputPanel". Connected with Ajax update/render does not work on a component which has rendered attribute

hide/show the panel using <p:command> and <p:outputpanel>

I am a new to jsf and primefaces.I want to implement that while clicking on button two link should be enable while clicking on the same button again that two link become disabled. I have created a example using <h:commandButton> and java bean to hide show but no idea with the <p:commandButton> and <p:outputPanel>.
I have achieved that while click on the link the 2 link will be enable.
Problem is but again clicking on that it has to be disable which was not working
If I understand you:
<h:form id="mainform">
<p:commandButton value="#{testBean.enabled ? 'Hide' : 'Show'}" action="#{testBean.toggle()}" update="links, #this"/>
<p:outputPanel id="links">
<p:link value="link1" href="http://www.stackoverflow.com" rendered="#{testBean.enabled}"/>
<p:spacer width="10"/>
<p:link value="link2" href="http://www.stackoverflow.com" rendered="#{testBean.enabled}"/>
</p:outputPanel>
</h:form>
Bean:
private Boolean enabled = false; // + getter/setter
public void toggle() {
enabled = !enabled;
}

Cannot show dialog in Primefaces RequestContext.execute() call

I have a tabview in which I want to refresh contents of one specific tab whenever user selects that tab. I also want modal dialog to pop up while tab is being refreshed.
Here is tabView with tabChange ajax event handler
<p:dialog widgetVar="statusDialog" modal="true" draggable="false" minimizable="false" appendToBody="true" closable="false" header="Processing..." resizable="false" maximizable="false">
<p:graphicImage library="assets" name="ajax-loader.gif"></p:graphicImage>
</p:dialog>
<p:tabView id="tabview" orientation="top" dynamic="false">
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"></p:ajax>
<p:tab title="tab1">
<ui:include src="/WEB-INF/views/tab1.xhtml"/>
</p:tab>
<p:tab title="tab2">
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID" name="refresh" global="true" onstart="statusDialog.show()" oncomplete="statusDialog.hide()"/>
<ui:include src="/WEB-INF/views/tab2.xhtml"/>
</p:tab>
</p:tabView>
Here is tabChangeListener:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
RequestContext.getCurrentInstance().execute("refresh()");
}
}
The refresh remoteCommand is being called as expected, but my statusDialog is never shown. If the same remoteCommand is triggered by a button click the statusDialog appears. There are no errors in JavaScript console.
Why is statusDialog not shown when remoteCommand is triggered by RequestContext.execute() and how can I make it appear? I even tried adding statusDialog.show() to execute() but it didnt help.
I figured it out. Here is the solution:
<h:outputScript>
var blockCount=0;
function showStatus() {
if (blockCount==0) statusDialog.show();
blockCount++;
};
function hideStatus() {
blockCount--;
if (blockCount==0) statusDialog.hide();
};
</h:outputScript>
<p:ajaxStatus onstart="showStatus();" onsuccess="hideStatus();" onerror="blockCount=0;statusDialog.hide();errorDialog.show();"/>
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID" name="refresh" global="true" onstart="showStatus()" oncomplete="hideStatus()"/>
Apparently the reason why my status dialog was not being shown is that another Ajax call finished and called statusDialog.hide() while my refresh() thing was going on. The JS code above maintains a counter of how many Ajax calls are in progress, and will only hide the status dialog when all calls have finished. Works as intended now!
If you want to show dialog when a specific tab is changed, you can inform a js function about, the tab selected control that it is 2 or not by adding a callback parameter via ajax response:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
RequestContext.getCurrentInstance().addCallbackParam("index", 2);
}
}
And use:
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"
oncomplete="showOrNot(xhr,status,args)"></p:ajax>
This will call the js function and it's going to control that the changed tab is 2 or not:
function showOrNot(xhr,status,args) {
if(args.index==2) {
statusDialog.show();
}
}
Or different approach is defining a value and using visible property of the p:dialog:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
this.condition=true;
}
}
And <p:dialog visible="#{bean.condition}"/>. And maybe you need to focus on your first approach and you can give an ID to p:dialog and update it via p:remoteCommand:
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID dialog" name="refresh" global="true" onstart="statusDialog.show()" oncomplete="statusDialog.hide()"/>
Don't forget to give the exact client ID of the dialog in the update property of p:remoteCommand.

primefaces accordion panel within single form - validation only on opened tab

I have checked around but I didn't found a clear example on how to submit the accordion using a single form.
The problem I find is when I want to process (validate) only fields of the opened tab.
The structure of my page is as follows:
<h:form>
<p:accordionPanel activeIndex="#{bean.selectedTab}">
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"/>
<p:tab title="Tab1" id="t1">
<p:inputText id="reqField1" required="true"/>
</p:tab>
<p:tab title="Tab2" id="t2">
<p:inputText id="reqField2" required="true"/>
</p:tab>
</p:accordionPanel>
<p:commandButton update="list" immediate="true" actionListener="#{bean.addRecord}"/>
</h:form>
method:
#SessionScoped
public class Bean{
public void tabChangeListener(AjaxBehaviorEvent evt){
AccordionPanel panel = (AccordionPanel) evt.getComponent();
// getLoadedTabs() returns an empty list
String currentlyLoadedTabId = panel.getLoadedTabs().get(this.selectedTab).getClientId();
}
}
Is there anyway to specify the id of the currently opened tab as part of the process attribute in p:commandButton tag?
UPDATE
When Tab1 is open, on submit, I want to be validated only reqField1 and not reqField2. Viceversa, when Tab2 is open, I want to be validated only reqField2 and not reqField1.
Try this.
Bind the activeIndex of the accordionPanel to a backing bean int attribute
activeIndex="#{myBean.selectedTab}"
Get the id of the currently selected tab using the bound activeIndex. To do this in your actionListener, get a handle on the accordion panel
EDIT: Since your actionListener has been set to immediate, the activeIndex and selectedTab will need to be updated via ajax. Add the following <p:ajax/> to your accordionPanel
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}" />
In your backing bean, you'll now have
public void (AjaxBehaviorEvent evt){
AccordionPanel panel = (AccordionPanel) evt.getComponent();
String currentlyLoadedTabId = panel.getLoadedTabs().get(this.selectedTab).getClientId();
}
Using the the id you got from 2 above, you can include that in the JSF list of things to be rerendered using ajax on the server side. In the same action listener method:
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add(currentlyLoadedTabId);
Alternatively, you might just consider placing a command button in each of those tabs and having a form in each tab as well. This way, each command button processes only it's own parent form

Resources