Check Tabs visited in p:tabView. Usage of onTabShow Event? - jsf-2

I am trying to track in a controller-bean, which tabs of a p:tabView were already visited (by tab-id).
I don't want to use the onTabChange event for some reasons (blocked already for other things).
So I tried to realize my usecase with onTabShow event of p:tabView. But did not succeed yet. I first tried with p:ajax listener:
<p:tabView>
<p:ajax event="tabShow" listener="#{myBean.checkTab(event)}" .../>
Result was error-message: tabShow not supported in p:ajax ...
Second try was using remoteCommand:
<p:tabView onTabShow="myCommand()">
...
<p:remoteCommand name="myCommand" actionListener="#{myBean.checkTab}" .../>
But how to pass the event as parameter to my bean-method to get the tab-object from?
Does somebody can help or has another idea how I can track the visited tabs in my bean?
With a binding of tabView perhaps? But how?
Thanks!

You can use the <p:ajax/> without specifying an event. That being said, you can get the currently selected tab either by
Binding the activeIndex property on the <p:tabView/> to a backing bean property
<p:tabView activeIndex="#{bean.selectedTabIndex}">
<p:ajax listener="#{myBean.checkTab}" .../>
</p:tabView>
With this variable bound, you can use it in checkTab.
Use the AjaxBehaviorEvent object to access the specific tab selected:
public void checkTab(AjaxBehaviorEvent abe){
TabView tb = (TabView) abe.getComponent();
List<Tab> loadedTabs = tb.getLoadedTabs();
Tab theTab = loadedTabs.get(tb.getActiveIndex());
}
and in your view:
<p:tabView>
<p:ajax listener="#{myBean.checkTab}"/>

Related

Ajax PrimeFaces not to render the event or disable checkbox

In doc it doesn't have a property render and i did a smoke test by having other components wrapping around p:ajax (Exception: but event attribute is unavailable) am i missing something here?
<p:ajax event="rowSelectCheckbox" listerner="somemethod()" update="someId"/>
Just omit the event totally:
<p:ajax listener="..." update="..."/>
It defaults to event="valueChange" and process="#this", which is often what one want.
If it does'nt work as expected check the Primefaces user guide, find your component and look for "Ajax behavior events" or look for attributes beginning with "on...".
About h:outputLink: its not a Primefaces tag so it should have been f:ajax for this one. However it does'nt work because of this.
Read more in this answer.
rowSelectCheckbox will be use with SelectEvent.
xhtml
<p:ajax event="rowSelectCheckbox" listerner="#{bean.selectCheckbox}" update="someId"/>
managedbean
public void selectCheckbox(SelectEvent event){
}

Dynamically add Primefaces Hotkey control

I am building an app where one of the requirements is heavy use of hotkeys. So heavy in fact that we want to pull those hotkeys back into a central controller.
The basic idea is each page will have a key associated with it. When jsf hits that key, it will go back to a central enummap to decide what hotkeys are supposed to be associated with that page and what methods are supposed to be added to the keys of that page.
My problem is the dynamic load. I can't use the
For now, I have this
<h:form binding="#{hotkeyController.form}">
<f:event listener="#{hotkeyController.genKeyHandler('HOTKETEST')}" type="preRenderComponent"/>
<p:outputPanel id="displayHotkey">
<h:outputText value="#{hotkeyController.keyText}" rendered="#{not empty hotkeyController.keyText}"/>
</p:outputPanel>
</h:form>
Then for my backing bean i have this
public void genKeyHandler(String pageKey) {
Hotkey hotkey = new Hotkey();
hotkey.setBind("ctl+shift+d");
hotkey.setAsync(true);
// "#{hotkeyController.keyHandler('HOTKETEST', 'F1')}"
hotkey.setActionExpression(createMethodExpression("#{hotkeyController.keyHandler('HOTKEYEXAMPLE', 'CTLSHIFTD')}", null,
String.class, String.class));
hotkey.setUpdate("displayHotkey");
form.getChildren().add(hotkey);
hotkey = new Hotkey();
hotkey.setBind("ctl+shift+a");
hotkey.setAsync(true);
// "#{hotkeyController.keyHandler('HOTKETEST', 'F1')}"
hotkey.setActionExpression(createMethodExpression("#{hotkeyController.keyHandler('HOTKEYEXAMPLE', 'CTLSHIFTA')}", null,
String.class, String.class));
hotkey.setUpdate("displayHotkey");
form.getChildren().add(hotkey);
}
Now this works in the sense that it actually inserts the hotkey into the form. I can see it in inspector. But, my problem is two fold. One, if I refresh the page, I get duplicate ID errors, if I use the preRenderView, I get "Error restoring component" errors. seems like no combination will work.
Is there any way to make this work? All I want is to have the bean method that inserts the hotkeys fire the first time a page is loaded and only fired once in the life of the page/view/whatever. This shouldn't be this hard.
My suggestion is that you use an exclusive form for the hotkeys.
Here is the sample:
<h:form id="mainForm">
<p:remoteCommand name="loadHotKeys" action="#{hotkeyController.genKeyHandler('HOTKETEST')}" update=":hotkeyForm" global="false" process="#this" />
<p:outputPanel id="displayHotkey">
<h:outputText value="#{hotkeyController.keyText}" rendered="#{not empty hotkeyController.keyText}"/>
</p:outputPanel>
</h:form>
<h:form id="hotkeyForm" binding="#{hotkeyController.form}" />
<script type="text/javascript">
jQuery(document).ready(loadForm());
</script>
And the genKeyHandler method should clear the hotkeyForm (form.getChildren().clear()) before adding the hotkeys.

Initial sortorder for PrimeFaces datatable with multisort

I am trying to implement multisort on Primeface datatable. We are using Primefaces v3.5. I have created a new load method in the LazyLoadClass that takes the List of SortMeta> parameter.
But I am having issues in the initial load of the table. The List of SortMeta> is null when the load method is called. I have also tried without specifying the initial sortBy and sortOrder for the datatable. In both the cases the result is the same.
Seeing that we have this new class SortMeta to support multisort, I suspect that the way to specify the initial sort field and order would have also changed. But I couldn't find any example anywhere to point the difference. The manual 3.5 doesn't mention any difference.
Why we could be getting the List of SortMeta> as null? Any pointers on example code where multisort is used with Lazyload?
I was able to get this to work.
Essentially we need to provide the UIColumn in the SortMeta object for it to work. For the initial sort at render time, I had to find the component in my bean and assign that to the sortMeta.
Below is my code in the view xhtml
<p:dataTable id="transDataTable" var="trans"
value="#{myBean.transModel}" paginator="true" rows="50"
paginatorAlwaysVisible="false" lazy="true"
sortMode="multiple" sortBy="#{myBean.preSortOrder}"
resizableColumns="true">
<p:column headerText="User" sortBy="#{trans.user.name}" >
#{trans.user.name}
</p:column>
<p:column headerText="Company" sortBy="#{trans.companyName}">
#{trans.companyName}
</p:column>
<p:column headerText="Join Date" id="joinDateTime"
sortBy="#{trans.joinDateTime}" >
<h:outputText value="#{trans.joinDateTime}" />
</p:column>
</p:dataTable>
Here is my bean code called on #PostConstruct
/*
* method to build initial sort order for multisort
*/
private void buildSortOrder() {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UIComponent column = viewRoot.findComponent("transDataTable:joinDateTime");
SortMeta sm1 = new SortMeta();
sm1.setSortBy((UIColumn)column);
sm1.setSortField("joinDateTime");
sm1.setSortOrder(SortOrder.DESCENDING);
preSortOrder.add(sm1);
}
I am not sure this is the right way to do this, but it works. I am usually uncomfortable when we have to use the ids from view in the bean code, as that can introduce bugs when people are not careful.
Thanks #CagatayCivici for the quick hint.

Select Item from many menu

Ok I have a simple many menu in wich I call a listener
<p:selectManyMenu style="width: 100%;" id="cmbsectores" valueChangeListener="#{mbcompletado.removeItem}">
<f:selectItems value="#{mbcompletado.sectores}"/>
<f:ajax update="#this"/>
</p:selectManyMenu>
I am looking the way I can use the ValueChangeEvent pass as parameter to detect which item was selected??
So I can use my business logic!
Do i need to use ajax tag? I found an itemSelect event in primeface, framework which I am using, but it only works on charts components!
Thanks in advance
Since you are already using PrimeFaces use p:ajax instead of f:ajax. The event is already set to the appropriate event (valueChanged).
To detect the selected values of the selectManyMenu the value attribute is necessary:
<p:selectManyMenu style="width: 100%;" id="cmbsectores"
value="#{mbcompletado.selectedSectores}">
<f:selectItems value="#{mbcompletado.sectores}"/>
<p:ajax/>
</p:selectManyMenu>
You can remove the valueChangeListener listener altogether.
For a more complete example see SelectManyMenu.
EDIT:
In your backing bean mbcompletado.selectedSectores should point to a collection of the same type like your mbcompletado.sectores. For example, if your sectores is a List of TypeA, selectedSectores should be also a List of the same type (TypeA).
Similar backing-bean structure can be found in the following example SelectManyCheckbox.
You need the <f:ajax listener> (or in this case better <p:ajax listener>) method instead. The ValueChangeListener serves an entirely different purpose and should only be used when you're really interested in both the old and new value, not when you're only interested in the new value.
E.g.
<p:selectManyMenu value="#{bean.selectedSectors>
<f:selectItems value="#{bean.availableSectors}"/>
<p:ajax listener="#{bean.selectedSectorsChanged}" />
</p:selectManyMenu>
with
private List<String> selectedSectors;
private List<String> availableSectors;
public void selectedSectorsChanged() {
System.out.println("Selected sectors are: " + selectedSectors); // Look, JSF has already set it.
// ...
}
See also:
When to use valueChangeListener or f:ajax listener?

set itemDisabled from backing bean method for each item in list

I have a radiobutton list and would like to disable some items according to the outcome of a backing bean method.
<h:selectOneRadio value="#{managedBean.selectedItem}">
<f:selectItems value="#{managedBean.selectItems}"
var="x"
itemDisabled="#{managedBean.checkIncompatible(x)}" />
</h:selectOneRadio>
Is this the right way to do it? Meaning, will this code call checkIncompatible(x) for each x from the selectItems list and set that item as enabled/disabled or just once and that's that?
I only managed to get all buttons to be either enabled or disabled and my suspicion is that the method only gets called once. Or that the rest of my code is not as perfect as I like to believe. And that would take a much longer question to fix.
I can't reproduce your problem on Mojarra 2.1.4 with the following view:
<h:selectOneRadio value="#{bean.item}">
<f:selectItems value="#{bean.items}" var="item"
itemDisabled="#{bean.isDisabled(item)}" />
</h:selectOneRadio>
and the following bean:
private String[] items = { "one", "two", "three" }; // +getter
private String item; // +getter+setter
public boolean isDisabled(String item) {
return "two".equals(item);
}
The above example correctly disables item two.
So, your problem is caused elsewhere, perhaps by a bug in checkUncompatible() method. A breakpoint on the method teaches me that it's definitely called for each item.

Resources