Dynamic primefaces menuItem don't fire command - jsf

Environment:
Java 7
Jboss 5.2
Primefaces 6.2
The problem I get is that when I click on the menu item the command does not fire the themeSwitcherBean.changeToOld method. What is wrong?
MenuModel menu = new DefaultMenuModel();
Create Menu
...
for (Iterator<Menu> it = children.iterator(); it.hasNext(); ) {
Menu subMenu = (Menu) it.next();
String index = subMenu.getCodi();
String element = rootCodi + index;
DefaultMenuItem menuItem = new DefaultMenuItem(menuName);
menuItem.setId(element);
menuItem.setUrl(subMenu.getServletPath());
menuItem.setCommand("#{themeSwitcherBean.changeToNew}");
menuItem.setUpdate(":content");
rootNode.addElement(menuItem);
}
menu.addElement(rootNode);
...
Menu.xhtml
<h:form id="frmMenu">
<pu:menu model="#{sessionBean.menu}">
</h:form>

If you set an URL to a menuItem.url property it is rendered as a simple hyperlink using href.
Clicking on this results in the browser to navigate to the given URL and request it using GET rather than doing a POST request optionally using AJAX.
This finally will not update ":content" the AJAX way and not invoke your themeSwitcherBean.changeToNew action method.
In order to have your action method invoke you have to skip that line:
menuItem.setUrl(subMenu.getServletPath());
If you find you need to reload the entire page (which is likely when switching themes) instead of the element referenced using ":content" only, make your action method return that instruction as String:
public String changeToNew() {
// do something ...
// ...
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
return viewId + "?faces-redirect=true&includeViewParams=true";
}
In this case you can disable AJAX on that menu item reducing the request/response/javaScript overhead a little bit:
menuItem.setAjax(false);

Related

How to add pe:badge to dynamically created menu in bean using PrimeFaces

I’m rewriting static menu to dynamic, since our customer wants to dynamically change the menu on the fly. Before that I had standard <p:menu> <p:menuItem> </p:menu> structure in my xhtml.
But now I have changed it to:
<p:menu model="#{pageTemplateView.menuModel}"/>
And I’m creating model in my backing bean like this:
DefaultMenuItem menuItem = new DefaultMenuItem();
menuItem.setIcon(item.getIcon());
menuItem.setTarget(item.getLink());
menuItem.setValue(item.getName());
But the problem is I don’t know how to add <pe:badge> component inside menu item from bean.
Before that I included badges to menus the following way:
<p:menuitem id="tasks_icon_menuitem_id" icon="fa fa-tasks" url="#">
<pe:badge content="#{badgeCountBean.badgeCount()}"/>
</p:menuitem>
So how do I add <pe:badge> to dynamically created menu in bean?
I'm using PrimeFaces 8
After few hours of testing and plying around I found the issue that prevents me from adding badge to default menu item.
The issue is when you try to add child to DefaultManuItem like this:
Badge badge = new Badge();
DefaultMenuItem defaultMenuItem = new DefaultMenuItem();
defaultMenuItem.getChildren().add(badge);
You get unsupported operation exception since DefaultMenuItem:: getChildren() is implemented like this:
public List<UIComponent> getChildren() {
return Collections.emptyList();
}
But I have found an ugly workaround for this issue. So I might share it and maybe well get to better solution eventuality.
In my xhtml I added empty menu and gave it fixed ID like this:
<!-- MENU PLACEHOLDER -->
<p:menu id="dynamic_menu_placeholder"/>
<!-- need to add dummy badge to xhtml otherwise it wont be displayed -->
<pe:badge/>
And then in my bean I got the component by ID and added UIMenuItem elements to it like this:
// get component by ID
UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(":form:dynamic_menu_placeholder");
Menu menu = (Menu) component;
menu.getChildren().clear();
for (MenuItem item : menuItemList) {
// creating menu item
UIMenuItem menuItem = new UIMenuItem();
menuItem.setUrl(item.getLink());
menuItem.setValue(item.getValue());
menuItem.setId(... generated some id);
// creating badge
Badge badge = new Badge();
badge.setContent(...getBadgeCount()..);
// adding badge to menu item
menuItem.getChildren().add(badge);
}
// addin menu item to menu
menu.getChildren().add(menuItem);

Primefaces wizard move to the next tab on an event

I have a prime faces wizard and a dataTable, my page successfully go to the next wizard tab if I selected an item from the dataTable, but my problem is when inserting a new data to the dataTable I want the wizard to go to the next tab if the insert was successful, any suggestions please?
You can use the client side API from backing bean, after the insert was successful.
Add a widgetVar to your wizard
<p:wizard widgetVar="wiz" ...>
...
<p/wizard>
Add the client execute, after the data is successfully inserted.
public void insertData() {
// Insert data
if (successfully) {
RequestContext context = RequestContext.getCurrentInstance();
context.execute("PF('wiz').next()");
}
}

How can be stopped automatic method call from #ManagedBean class at page refresh, JSF

In my XHTML page I'm calling a method from my #ManagedBean class. The method should be executed only when I click the link which to is linked the method:
<h:link value="Continue Reading »"
outcome="contracts/resources/data/imag2_facebook.html"
onclick="#{sessionFilter.incForLink2('contracts/resources/imagini/facebook.jpg','Facebook down? Current problems and status', 'contracts/resources/imagini/facebook.jpg')}" />
It's weird why the method is executed at every page refresh without clicking on the link. I want the method to execute only when I click on the link. I have also tried with h:commandLink but the results are the same. Do you have an idea what I need to change, or what is wrong? The #ManagedBean class is application scoped. The method I call is the following:
public void incForLink2(String link, String title, String imgAllLink) {
Article article = links.get(link);
if (article != null) {
Integer pageHits = article.getPageHits();
article.setPageHits(pageHits + 1);
System.out.println(link + " = " + pageHits);
} else {
Article article1 = new Article(1, title, link, imgAllLink);
links.put(link, article1);
}
}
onClick is a handler for JavaScript in the webbrowser! The Method you call is Java and executed on the server!
Java renders the Website before the website is sent to the webbrowser, in this phase is the method is invoked. After the sending to the webbrowser the javascript can be executed, this is a second phase. You simply need a new request to the server for executing java-methods. I prefer to use a4j:jsFunction.

Redirect my page after h:commandLink action in JSF [duplicate]

This question already has answers here:
Creating master-detail pages for entities, how to link them and which bean scope to choose
(2 answers)
Closed 7 years ago.
I have two pages:
listMedicalJourneys.xhtml
listAffectedEmployees.xhtml
From the first page:
<h:form>
<h:commandLink action="#{MedicalJourneyController.listAffectedEmployees()}" value="Manage">
<f:setPropertyActionListener value="#{element.id}" target="#{MedicalJourneyController.medicalJourneyId}" />
</h:commandLink>
</h:form>
The #RequestScoped bean #{MedicalJourneyController} has this method:
public String listAffectedEmployees() {
MedicalJourney m = medicalJourneyBean.getMedicalJourneyById(medicalJourneyId);
setMesList(new ArrayList<MedicalJourneyEmployeeService>(m.getMedicalJourneyEmployeeServices()));
setSelectedMedicalJourney(m);
return "listAffectedEmployees.faces?faces-redirect=true";
}
When I use the redirect to change URL, the next page doesn't show the selected value.
if i understand you right, you want to select an item inside one view, and display its SubItems in the next View. if this is the Case then, there are seviral ways to acheave this, here i will show you a way based on your Concept/Code above, so lets assume the following:
listMedicalJourneys.xhtml the View where you select an Item
listAffectedEmployees.xhtml the view Where you display SubItems of the preselected Item
and i assume that you have for each View its own Controller/ManagedBean,
so lets call the first one medicalJourneysManager and for the second view affectedEmployeesManager, both are requestScoped Beans
in the medicalJourneysManager your "selection Methode" action event should only get the selected ItemId, and pass this selected id to the next Page. Next Page Controller should then load the List of SubItems. Because a requestScoped Bean is only available during this single request, and as soon as you navigate anywhere, your bean will be reinitialized, that means the loaded data is lost at this moment.
so in your medicalJourneysManager define some ActionMethode like this:
//JSF 2.+
public String selectMedicalJourny(int medicalJourneyId) {
// do what ever you want before redirect, i.e. any validations, ...etc if required
return "listAffectedEmployees.faces?faces-redirect=true&medicalJourneyId="+medicalJourneyId;
}
this will redirect you to the next View where you display a list of AffectedEmployees
this new View needs its Controller "affectedEmployeesManager" to load the list of affectedEmployees.
so in the this managed Bean do something like this:
#PostConstruct
private void init(){
try{
String medicalJourneyId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("medicalJourneyId");
// now do whatever you want with it, load its subNodes/affectedEmployeesList, ...etc
MedicalJourney m = medicalJourneyBean.getMedicalJourneyById(medicalJourneyId);
setMesList(new ArrayList<MedicalJourneyEmployeeService>(m.getMedicalJourneyEmployeeServices()));
setSelectedMedicalJourney(m);
}catch(Exception e){
e.printStackTrace();
}
}
a simpler alternative to commandLink is using a direct link with that param without any action commands.
here is a helpfull link.

How to apply Primefaces effect when component is rendered

i have drag panel and drop panel, and when component is dropped in the drop panel i show a new panel and hide the old panel based on render boolean attribute as follows:
1- xhtml:
<p:outputPanel id="oldPanel" rendered=#{myBean.old_panel_rendered}> .... </p:outputPanel>
<p:outputPanel id="newPanel" rendered=#{myBean.new_panel_rendered}> .... </p:outputPanel>
2- bean:
old_panel_rendered=true;
new_panel_rendered=false;
public void onComponentDrop(DragDropEvent ddEvent) {
old_panel_rendered=false;
new_panel_rendered=true;
}
how to execute an effect for newPanel when it gets rendered and execute an effect for oldPanel when it gets unrendered.
please advise, thanks.
Call js function which will apply the effects when a new item droppped:
<p:ajax listener="#{bean.onDrop}" onstart="applyEffects();" update="newPanel" />
Function is:
function applyEffects() {
var oldPanel = $(document.getElementById('oldPanel'));
var newPanel = $(document.getElementById('newPanel'));
oldPanel.css({"display":"none"});//or oldPanel.fadeOut(500) which looks fancy
newPanel.css({"display":"inline"});
newPanel.effect("highlight",
{color:"#87FF7A"}, 1500);
}
Don't forget to give exact client id of components when calling document.getElementById. You can detect it via your browser's developer settings. If there will be a problem, you can drop update="newPanel" or maybe you can try update="oldpanel newpanel".
To be able to apply it for specific panel:
public void onComponentDrop(DragDropEvent ddEvent) {
int id = event.getData();//or sth.similar to getId
RequestContext.getCurrentInstance().addCallbackParam("index", id);
}
Upper code adds a parameter to ajax response it can be retrieved by:
function applyEffects(xhr,status,args) {
var oldPanel = $(document.getElementById('oldPanel'));
var newPanel = $(document.getElementById('newPanel'));
if(args.id=='oldPanel') {//oldPanel or whatever which equals to eventID
oldPanel.css({"display":"none"});//or oldPanel.fadeOut(500) which looks fancy
}
newPanel.css({"display":"inline"});
newPanel.effect("highlight",
{color:"#87FF7A"}, 1500);
}
You should call this from p:ajax oncomplete="applyEffects(xhr,status,args);". I am coding directly here, therefore can be few mistakes which can be seen on IDE easily.

Resources