Stateless and stateful theme switchers

Multi-theme web applications require a theme switcher component. The default PrimeFaces' theme switcher is a component which enables switching themes on the fly, without sending an AJAX or a full-page request. We speak about a stateless theme switcher because the current selected theme is only known on the client side. Users also often need a stateful theme switcher to save the chosen theme on the server side in user preferences or settings.

In this recipe, we will show the usage of a stateless theme switcher and implement a stateful theme switcher, which is able to save the current selected theme on the server side.

How to do it…

The theme switcher usage is very similar to the usage of p:selectOneMenu. The component is represented by the p:themeSwitcher tag and accepts f:selectItem or f:selectItems. The code snippet for a stateless theme switcher is as follows:

<p:themeSwitcher style="width:165px" effect="fade">
  <f:selectItem itemLabel="Choose Theme" itemValue=""/>
  <f:selectItems value="#{userSettingsBean.themes}"/>
</p:themeSwitcher>

Themes are prepared in a CDI bean UserSettingsBean:

@Named
@SessionScoped
public class UserSettingsBean implements Serializable {

  private Map<String, String> themes;

  public Map<String, String> getThemes() {
    return themes;
  }

  @PostConstruct
  public void init() {
    themes = new TreeMap<String, String>();
    themes.put("Afterdark", "afterdark");
    ...
    themes.put("Vader", "vader");
  }
}

The next code snippet demonstrates a stateful theme switcher:

<p:themeSwitcher value="#{userSettingsBean.theme}" var="t"
  style="width:170px" effect="fade"
  converter="#{themeConverter}"
  onchange="$('#mainForm').submit()">
  <f:selectItems value="#{userSettingsBean.availableThemes}"
    var="theme"
    itemLabel="#{theme.displayName}"
    itemValue="#{theme}"/>
  <p:column>
    <h:graphicImage library="images"
      name="themes/#{t.name}.png"/>
  </p:column>
  <p:column>
    #{t.displayName}
  </p:column>
</p:themeSwitcher>

It supports the display of theme previews in the form of small images.

How to do it…

The implementation requires p:column. This theme switcher sends full-page requests when the user changes themes. UserSettingsBean is a bean class providing getters / setters for the current selected theme and a public method List<Theme> getAvailableThemes(). This method returns all available themes as a list of instances of type Theme. The model class Theme consists of two attributes, displayName and name:

public class Theme implements Serializable {

  private String displayName;
  private String name;

  public Theme(String displayName, String name) {
    this.displayName = displayName;
    this.name = name;
  }

  // getters
  ...
}

How it works…

The resource URL to theme.css contains a current theme name. The stateless theme switcher changes the theme name in the resource URL by JavaScript. The changed resource link streams down a new theme.css to the page dependent on the user selection.

In the second example for the stateful theme switcher, we defined a JavaScript onchange callback to submit the closest form with a current selected theme. It results in a regular HTTP request. The p:column tag is needed to display table-like custom content. The model class Theme encapsulates the displayed name and the name of the picture for every single theme and exposes this information on the page via the var attribute.

In case you would like to be notified when a user changes the theme (for example, to update user preferences), you can use an attached p:ajax:

<p:themeSwitcher value="#{userSettingsBean.theme}">
  <f:selectItems value="#{userSettingsBean.themes}"/>
  <p:ajax listener="#{userSettingsBean.saveTheme}"/>
</p:themeSwitcher>

There's more…

We used a JSF converter for the stateful theme switcher, which was developed as a CDI bean. The converter as bean allows to inject another bean into the converter instance. In our case, we injected an instance of UserSettingsBean:

@Named
@SessionScoped
public class ThemeConverter implements Serializable, Converter {

  @Inject
  private UserSettingsBean userSettingsBean;

  public Object getAsObject(FacesContext context, UIComponent component, String value) {
    List<Theme> themes = userSettingsBean.getAvailableThemes();
    for (Theme theme : themes) {
      if (theme.getName().equals(value)) {
        return theme;
      }
    }

    return null;
  }

  public String getAsString(FacesContext context, UIComponent component, Object value) {
    return ((Theme) value).getName();
  }
}

PrimeFaces Cookbook Showcase application

This recipe is available in the demo web application on GitHub (https://github.com/ova2/primefaces-cookbook/tree/second-edition). Clone the project if you have not done it yet, explore the project structure, build and deploy the WAR file on every Servlet 3.x compatible application server such as JBoss WildFly or Apache TomEE.

The showcase for the recipe is available at http://localhost:8080/pf-cookbook/views/chapter2/statelessThemeSwitcher.jsf and http://localhost:8080/pf-cookbook/views/chapter2/statefulThemeSwitcher.jsf.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.97.202