0

I'm starting a new application and I'm trying to build the main menu's structure to update the content section using AJAX. I'm using JSF 2.2 and Primefaces 6.1. The structure of my project is as follows:

template.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>...</h:head>

<h:body>
    <div id="header">
        <ui:insert name="header">...</ui:insert>
    </div>

    <div id="menu">
        <ui:insert name="menu"></ui:insert>
    </div>

    <h:panelGroup layout="block" id="content" styleClass="container">
        <ui:insert name="content">Default content</ui:insert>
    </h:panelGroup>

    <div id="footer">...</div>
</h:body>
</html>

home.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:f="http://xmlns.jcp.org/jsf/core"
                xmlns:p="http://primefaces.org/ui"
                template="./resources/templates/template.xhtml">

    <ui:define name="menu">
        <h:form id="form-menu">
            <p:menubar id="menubar">
                <p:menuitem id="menuitem-home" value="Home" actionListener="#{navigation.navigate}" update="@(content)" process="@(form-menu)"/>
                <p:submenu id="submenu" label="Submenu">
                    <p:menuitem id="menuitem-option1" value="Option 1" actionListener="#{navigation.navigate}" update="@(content)" process="@(form-menu)"/>
                    <p:menuitem id="menuitem-option2" value="Option 2" actionListener="#{navigation.navigate}" update="@(content)" process="@(form-menu)"/>
                    <p:menuitem id="menuitem-option3" value="Option 3" actionListener="#{navigation.navigate}" update="@(content)" process="@(form-menu)"/>
                </p:submenu>
            </p:menubar>
        </h:form>
    </ui:define>

    <ui:define name="content">
        <ui:include src="#{navigation.targetPartial}" />
    </ui:define>
</ui:composition>

welcome/option1/option2/option3.xhtml (partials)

This is for filling <ui:include>. They have all the same structure so I resume it in the same place:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:body>
    <h1 class="h1">My application</h1>
    <h3 class="h3">Welcome/Option1/Option2/Option3</h3>
</h:body>   
</html>

home.xhtml is located at src/main/webapp/, template.xhtml in src/main/webapp/resources/templates/ and partials in src/main/webapp/resources/partials/. My bean is a simple navigation handler, made as follows:

Navigation.java

@Named("navigation")
@SessionScoped
public class Navigation implements Serializable {
    private static final long serialVersionUID = 6657512604418974978L;
    private static final String PARTIALS_ROOT_FOLDER = "/resources/partials/";
    private static final String XHTML_EXTENSION = ".xhtml";

    private String targetPartial = "welcome";
    private Map<String, String> idToPartialMap;

    @PostConstruct
    public void init() {
        idToPartialMap = new HashMap<>();
        idToPartialMap.put("menuitem-home", "welcome");
        idToPartialMap.put("menuitem-option1", "option1");
        idToPartialMap.put("menuitem-option2", "option2");
        idToPartialMap.put("menuitem-option3", "option3");
    }

    public String getTargetPartial() {
        return PARTIALS_ROOT_FOLDER + targetPartial + XHTML_EXTENSION;
    }

    public void setTargetPartial(final String targetPartial) {
        this.targetPartial = targetPartial;
    }

    public void navigate(final ActionEvent event) {
        setTargetPartial(idToPartialMap.get(event.getComponent().getId()));
    }

}

So, the idea is: Navigation is initialized at welcome so the home page is rendered first in <ui:include src="#{navigation.targetPartial}"/> (that works fine). idToPartialMap maps (forgive the redundancy) from <p:menuitem> id to corresponding partial name.

After that, when you click any option in the menu, the <ui:define name="content"> section should be updated using an AJAX request. The objective is to optimize network traffic by keeping the fixed sections of the page and just updating the content section.

The current situation

Reading the documentation I saw Primefaces 6.1 now support jQuery selectors to target any component using ids or classes.

With the project as it is the page renders correctly but when I click any option the page blinks but doesn't change. If I reload the page it renders the optionX page, proving that Navigation#targetPartial has been changed through navigate() method. Inspecting the network traffic you can see that home.xhtml is first loaded with an HTTP GET with type Document. In subsequent clicks in the menu, the same file is loaded but with type 'XHR' (XML HTTP Request). AFAIK, this is the AJAX request fired by the update attribute in <p:menuitem>, am I correct?

What am I missing here? how can I make it work? Changing update="@(content)" to update="@all" solves the problem but the whole page is loaded and that's not the idea.

Any ideas, suggestions and guideline is welcomed. Thanks in advance for your answers.

Alvaro Pedraza
  • 1,176
  • 6
  • 20
  • 44
  • If you're trying to target an id to update or process, just use the id itself. I've had trouble getting IDs to work with PF selector like that. Just use like `update="content"`. [Here's](https://stackoverflow.com/questions/20080861/how-do-primefaces-selectors-as-in-update-myclass-work) a great explanation of PF selectors by BalusC. – Mitchell Brooks Feb 01 '18 at 12:58
  • I tried that already and it was throwing an exception at runtime. It’s working that way so I leave it there. I’ve been reading about selectors and should work as you said, but for some reason it isn’t (at least in my computer). I’ll check the link, and if you can figure out how to fix my syntax, it’s also welcomed. Best regards – Alvaro Pedraza Feb 01 '18 at 17:21

0 Answers0