I'm learning JSF 2.2 and trying to make a Single Page Application (SPA). Using version 2.2.8. I have made a simple SPA that only displays text and pictures. I made it by using f:ajax, ui:include and ui:composition.
It all starts in the index.xhtml file:
<!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://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<h:head>
<title>Project S - SPA</title>
<link href="./css/styles.css" rel="stylesheet" type="text/css"/>
</h:head>
<h:body>
<h1 class="title">Project S - Single Page Application</h1>
<h:form>
<f:ajax render="content">
<h:commandLink value="Login" action="#{navController.setToPage('login')}"/>
<h:commandLink value="Create user" action="#{navController.setToPage('create-user')}"/>
<h:commandLink value="Reset password" action="#{navController.setToPage('reset-password')}"/>
</f:ajax>
</h:form>
<hr/>
<div jsf:id="content">
<ui:include src="#{navController.page}.xhtml"/>
</div>
</h:body></html>
From here I load pages like login.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h1>Login page</h1>
<h:form>
Please log in.<br/>
<h:panelGrid columns="2">
User name: <h:inputText value="#{loginController.name}"/>
Password: <h:inputSecret value="#{loginController.password}"/>
</h:panelGrid>
<h:commandButton value="Login" action="#{loginController.login}"/>
</h:form>
</ui:composition>
and create-user.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h1>Create user page</h1>
<h:form>
<h:panelGrid columns="3" styleClass="formTable">
User name:
<h:inputText value="#{registerController.userName}"
id="uname"
required="true"
requiredMessage="Please enter your User Name">
</h:inputText>
<h:message for="uname"/>
Password:
<h:inputSecret value="#{registerController.password}"
id="pass"
required="true"
requiredMessage="Please enter your Password">
</h:inputSecret>
<h:message for="pass"/>
Hint:
<h:inputText value="#{registerController.hint}"
id="hint"
required="true"
requiredMessage="Please enter a hint">
</h:inputText>
<h:message for="hint"/>
</h:panelGrid>
<h:commandButton value="Register" action="#{registerController.register}"/>
</h:form>
</ui:composition>
I use the NavController.java Managed bean to navigate them:
package controllers;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class NavController implements Serializable {
private static final long serialVersionUID = 1L;
private String page = "login";
public String getPage() {
return page;
}
public void setToPage(String page) {
this.page = page;
}
}
The pages work fine for showing up and switching to them. The first page that will load, in this case login, will work with no problem. But the other pages do not. And by do not I mean that no matter what I input when I click the h:commandButton, neither the validation is activated, nor is the user created. I just get sent back to the index.jsf page. Here is the controller class for create-user:
package controllers;
import javax.faces.bean.ManagedBean;
import database.UsersDataBaseSimulator;
import models.User;
@ManagedBean
public class RegisterController {
private String userName, password, hint;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
public String register() {
if(UsersDataBaseSimulator.USERS.containsKey(userName)) {
return "user-exists";
}
User user = new User(userName, password, hint);
UsersDataBaseSimulator.USERS.put(userName, user);
return "user-created-successfully";
}
}
And the controller class for the login:
package controllers;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import database.UsersDataBaseSimulator;
@ManagedBean(name="loginController")
@SessionScoped
public class LoginController implements Serializable{
private static final long serialVersionUID = 1L;
private String name, password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String login() {
if(UsersDataBaseSimulator.USERS.get(name) != null) {
if(UsersDataBaseSimulator.USERS.get(name).getPassword().equals(password)) {
return "main-page?faces-redirect=true";
}
}
return "error";
}
}
I have created this page as a non SPA and it works fine. I've tried to switch the initial page from login to create-user and in that case only the create-user page works. At this point I don't know if this is even possible and if I am going about it the right way. I'm learning from this course http://www.coreservlets.com/JSF-Tutorial/jsf2/. So far I've finished it up to Composite Components part 1. I'll provide any additional information that you might need in order to get to the bottom of this problem. Thank you in advance to anybody that takes the time to tackle this problem.