Enabling/disabling tabs programatically

As I was reading the JBoss RichFaces forum, I saw this post. Here is one possible solution.

screenshot01.png

<h:form>
   <h:panelGrid columns="3">
	<a4j:commandButton id="tab1"
		value="#{tabsBean.tabsMap['tab1']?'Enable':'Disable'} Tab 1"
		actionListener="#{tabsBean.disable}" reRender="tab1">
		<a4j:actionparam name="value" value="#{!tabsBean.tabsMap['tab1']}"
			assignTo="#{tabsBean.value}" />
		</a4j:commandButton>
 
	<a4j:commandButton id="tab2"
		value="#{tabsBean.tabsMap['tab2']?'Enable':'Disable'} Tab 2"
		actionListener="#{tabsBean.disable}" reRender="tab2">
		<a4j:actionparam name="value" value="#{!tabsBean.tabsMap['tab2']}"
			assignTo="#{tabsBean.value}" />
	</a4j:commandButton>
 
	<a4j:commandButton id="tab3"
		value="#{tabsBean.tabsMap['tab3']?'Enable':'Disable'} Tab 3"
		actionListener="#{tabsBean.disable}" reRender="tab3">
		<a4j:actionparam name="value" value="#{!tabsBean.tabsMap['tab3']}"
			assignTo="#{tabsBean.value}" />
	</a4j:commandButton>
   </h:panelGrid>
</h:form>
<a4j:outputPanel ajaxRendered="true">
   <rich:tabPanel switchType="ajax" width="200px" id="tabs">
	<rich:tab label="Tab 1" disabled="#{tabsBean.tabsMap['tab1']}">
		Tab 1
	</rich:tab>
	<rich:tab label="Tab 2" disabled="#{tabsBean.tabsMap['tab2']}">
		Tab 2
	</rich:tab>
	<rich:tab label="Tab 3" disabled="#{tabsBean.tabsMap['tab3']}">
		Tab 3
	</rich:tab>
	</rich:tabPanel>
</a4j:outputPanel>

TestBean.java class:

package test;
 
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.faces.event.ActionEvent;
 
 
public class TabsBean {
 
   private HashMap <String, Boolean>tabsMap;
   private Boolean value;
 
   // setters and getters
 
   @PostConstruct
   public void create (){
	tabsMap = new HashMap<String, Boolean> ();
	tabsMap.put("tab1", false);
	tabsMap.put("tab2", false);
	tabsMap.put("tab3", false);
   }
 
   public void disable (ActionEvent event) {
	String id = event.getComponent().getId();
	tabsMap.put(id, value);
   }
   public TabsBean() {}
}

Bean registration in JSF configuration file (manage bean in session scope in order to remember enabled/disabled tab state between requests):

 <managed-bean>
  <managed-bean-name>tabsBean</managed-bean-name>
  <managed-bean-class>test.TabsBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
 </managed-bean>

Share/Save/Bookmark

JSFDays*09, Vienna, Austria

JSFDays*09 will be held for the second year in beautiful Vienna, Austria on April 1-3, 2009. The conference is full of JSF superstars: Ed Burns, Matthias Wessendorf, Martin Marinschek, Cagatay Civici, Kito Mann, Pete Muir, Pourya Harirbafan and many more. It’s going to be a great conference.

I have two sessions and a full day RichFaces workshop.

April 1st, 2009
Building RIA applications with JBoss RichFaces

April 2nd, 2009
Buillding RIA applications with JavaFX

April 3rd, 2009
Full day, hands-on RichFaces workshop

If you want to quickly learn RichFaces, definitely attend the full day workshop.

Share/Save/Bookmark

Keeping rich:panelMenu state

This example is in response to this post.

The solution uses two managed beans, one in request and one in session scope. The session bean will keep the menu state. You can easily extend this example to use Seam. I need to remember two things. First is which group was opened/closed and second which item inside the group was clicked. Remembering which item inside the group was clicked is done via selectedChild=”#{menuState.selectedMenuItem}”. Remembering which group was opened is done via value attribute on each group. The value is saved automatically.

I’m setting action=”page.xhtml” because I’m using a custom navigation handler. Standard navigation rules will work the same way.

start.xhtml:

<h:form>
<rich:panelMenu style="width:200px" mode="client" 
  selectedChild="#{menuState.selectedMenuItem}"
  iconExpandedGroup="disc" 
  iconCollapsedGroup="disc" 
  iconExpandedTopGroup="chevronUp" 
  iconGroupTopPosition="right" 
  iconCollapsedTopGroup="chevronDown" 
  iconCollapsedTopPosition="right" >
  <rich:panelMenuGroup label="Group 1" id="group1" 
                value="#{menuState.menu['group1']}">
	<rich:panelMenuItem label="Item 1" id="group1_item1" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
	<rich:panelMenuItem label="Item 2" id="group1_item2" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
	<rich:panelMenuItem label="Item 3" id="group1_item3" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
   </rich:panelMenuGroup>
   <rich:panelMenuGroup label="Group 2" id="group2" 
               value="#{menuState.menu['group2']}" >
       <rich:panelMenuItem label="Item 1" id="group2_item1" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
	<rich:panelMenuItem label="Item 2" id="group2_item2" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
	<rich:panelMenuItem label="Item 3" id="group2_item3" 
		actionListener="#{menuBean.select}"
		action="/select.xhtml"
		mode="server"/>
   </rich:panelMenuGroup>
</rich:panelMenu>
</h:form>

MenuBean managed bean (in request scope):

 
package test;
 
import javax.faces.event.ActionEvent;
 
public class MenuBean {
 
   private MenuState menuState;
 
   public MenuState getMenuState() {
	return menuState;
   }
   public void setMenuState(MenuState menuState) {
	this.menuState = menuState;
   }
   public MenuBean() {}
 
   public void select (ActionEvent event) {
	menuState.setSelectedMenuItem(event.getComponent().getId());
   }
}

In select listener, we are remembering which rich:panelMenuItem was clicked. When we come back to the page, the clicked item will be italicized via selectedChild=”#{menuState.selectedMenuItem}”.

MenuState bean (in session scope) keeps the menu state.

package test;
 
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
 
public class MenuState {
 
private Map <String, Boolean> menu;
 
   private String selectedMenuItem;
 
   public String getSelectedMenuItem() {
	return selectedMenuItem;
   }
   public Map<String, Boolean> getMenu() {
	return menu;
   }	
   public void setMenu(Map<String, Boolean> menu) {
	this.menu = menu;
   }
   public void setSelectedMenuItem(String selectedMenuItem) {
	this.selectedMenuItem = selectedMenuItem;
   }
   public MenuState() {
   }
   @PostConstruct
   public void init () {
	menu = new HashMap <String, Boolean>();
	menu.put("group1", false);
	menu.put("group2", false);
   }
}

rich:panelMenuGroup value attribute is bound to the menu HashMap and is saved automatically.

JSF configuration file:

 <managed-bean>
  <managed-bean-name>menuBean</managed-bean-name>
  <managed-bean-class>test.MenuBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
   <property-name>menuState</property-name>
   <property-class>test.MenuState</property-class>
   <value>#{menuState}</value>
  </managed-property>
 </managed-bean>
 
 <managed-bean>
  <managed-bean-name>menuState</managed-bean-name>
  <managed-bean-class>test.MenuState</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
 </managed-bean>

select.xhtml is very simple:

<body>
   <h:form>
  	Go <h:commandLink action="/start.xhtml" value="Back" />
   </h:form>
</body>

Share/Save/Bookmark

United 1K again

I made it United 1K again. This means I flew more then 100,000 miles this year. I did have to do a number of mileage runs (I flew a little bit less as my daughter was born this year), but trust me it’s worth it. Being an elite flyer, the travel experience is usually enjoyable compared to the horror stories you hear in the news. You get priority everything - checking in, boarding, seating. You also get free upgrades. For example, when you fly to Europe (that’s about 11+ hours from San Francisco) I have a good chance of being upgraded to Business class basically for free (after purchasing a regular economy ticket). To buy a Business class ticket would cost at least $5,000.

If you fly a lot, it makes a lot of sense to fly the same airline.

Share/Save/Bookmark

Two articles in Top 10 on JavaLobby.com of 2008

Two articles I wrote are in JavaLobby’s Top 10 Articles of 2008 by James Surgue. Thank you, it’s nice to be in top ten.

  1. Interview: John De Goes Introduces a Newly Free Source Code Editor
  2. An Introduction To JBoss RichFaces (by me)
  3. The Best Java Tools You Never Knew Existed
  4. Using JSF and Flex Components Together (by me)
  5. Ten Amazing Java Applications
  6. Looking Forward to JPA 2.0
  7. Tomcat Today, GlassFish Tomorrow?
  8. Is Hibernate the best choice?
  9. Google Android Tutorial
  10. Pathway from ACEGI to Spring Security

The placement is based on number of clicks the article received. If this article was published today my An Introduction To JBoss RichFaces article would take first place as it has 42,012 clicks while Interview: John De Goes Introduces a Newly Free Source Code Editor has 41, 380. Oh well, next year :).

Early next year an article on how to use RichFaces with Spring will be published.

Share/Save/Bookmark

XML-less JSF Navigation

Cagatay Civici posted a very neat example of using JSF navigation without XML (without defining navigation rules in JSF configuration file). I simplified the custom navigation handler even further. It is safe to assume that most people today use Facelets (I do in all my projects and trainings, plus it’s going to be used in JSF 2.0), so we don’t have to check the javax.faces.DEFAULT_SUFFIX context param. So, instead of using:

public String navigate () {
  return "somepage"
}

it’s now possible to use this:

public String navigate () {
  return "/somepage.xhtml"
}
<h:commandButton value="Submit" action="#{bean.navigation}"/>

or even like this if there is no action:

<h:commandButton value="Submit" action="/somepage.xhtml"/>

getTargetViewId method now looks like this:

private String getTargetViewId(FacesContext facesContext, String outcome) {
   String targetViewId;
 
   if (isRedirect(outcome)){
      targetViewId = outcome.split(":")[1];
   } else {
      targetViewId = outcome;
   }
}

Thanks Cagatay for posting this!

Share/Save/Bookmark

Practical RichFaces - available on Amazon

Practical RichFaces book hard copy is now available on Amazon.

Share/Save/Bookmark

Practical RichFaces - final PDF version uploaded

If you downloaded a PDF copy of Practical RichFaces book before December, the publisher has uploaded the final version. Download the new version.

Hard copy will be available very soon as well I’m told (1-3 weeks).

Share/Save/Bookmark

Practical RichFaces book - few free PDF copies left

I’ve got a few free PDF copies left of my Practical RichFaces book. Email me (max at exadel dot com) if you want one.

Share/Save/Bookmark

JavaFX - Rich Internet Applications with Java

Tomorrow, December 4th, 2008 JavaFX 1.0 is going to be released. JavaFX is a new open source scripting language that runs inside the new, more lightweight, but still familiar, Java runtime environment.

I’m (mildly) excited. Excited - Java is a great technology for building web user interfaces, but it failed in a few areas in the past. Mildly - JavaFX was announced at JavaOne 2007 but only now we are getting version 1.0. JavaFX has a long way to go before companies are using it to build real world RIA applications. Today the choice is still Flex or Silverlight. However, I do believe with the 1.0 release, companies will start playing with it. Enterprise tools for building RIA applications is shaping to be something like this:

HTML/AJAX (pure browser)
Flash/Flex (browser + plug-in)
Silverlight (browser + plug-in)
JavaFX (browser + plug-in)

Exadel already offers some basic JavaFX tooling for enterprise applications. With Exadel Flamingo you can easily connect JavaFX with Seam or Spring back ends.

Share/Save/Bookmark

Next Page »