JSF Example with Ajax insert and delete..

Here we go.

Directory Layout

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>ajaxtable</artifactId>
    <packaging>war</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>ajaxtable</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>javax.faces-api</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.13</version>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>ajaxtable</finalName>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.1.v20140609</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                    <webApp>
                        <contextPath>/</contextPath>
                    </webApp>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
 
    <servlet>
        <servlet-name>faces-servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>faces-servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
 
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
 
</web-app>

Student.java
package biz.tugay.ajaxtable;
 
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 7/3/2016
 * Time: 1:16 PM
 */
 
@ManagedBean
@RequestScoped
public class Student {
 
    private String firstname;
    private String lastname;
 
    public Student() {
    }
 
    public Student(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }
 
    public String getFirstname() {
        return firstname;
    }
 
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
 
    public String getLastname() {
        return lastname;
    }
 
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
 
}

StudentTableBacking.java
package biz.tugay.ajaxtable;
 
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import java.util.ArrayList;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 7/3/2016
 * Time: 1:17 PM
 */
 
@ManagedBean
@ApplicationScoped
public class StudentTableBacking {
 
    private final List<Student> studentList = new ArrayList<Student>();
 
    {
        studentList.add(new Student("koray", "tugay"));
    }
 
    public void addStudent(Student student) {
        studentList.add(student);
    }
 
    public List<Student> getStudentList() {
        return studentList;
    }
 
    public void deleteStudent(Student student) {
        studentList.remove(student);
    }
}

index.xhtml
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>AjaxTable</title>
</h:head>
<h:body>
    <h:outputScript name="/js/fixajax.js" target="head"/>
    <div>
        <h1>Current Students:</h1>
        <h:dataTable id="studentsTable" value="#{studentTableBacking.studentList}" var="student">
            <h:column id="tablefirstnamecolumn">
                <f:facet name="header">First Name</f:facet>
                <h:outputText value="#{student.firstname}"/>
            </h:column>
            <h:column id="tablelastnamecolumn">
                <f:facet name="header">Last Name</f:facet>
                <h:outputText value="#{student.lastname}"/>
            </h:column>
            <h:column id="deleteStudent">
                <h:form>
                    <h:commandButton value="Delete Student">
                        <f:ajax listener="#{studentTableBacking.deleteStudent(student)}"
                                execute="studentsTable"
                                render="studentsTable"/>
                    </h:commandButton>
                </h:form>
            </h:column>
        </h:dataTable>
    </div>
    <br />
    <div>
        <h:form id="addStudentForm" prependId="false">
            <h:outputLabel id="firstnameLabel" for="firstname" value="First Name: ">
                <h:inputText id="firstname" value="#{student.firstname}"/>
            </h:outputLabel>
            <br/>
            <br/>
            <h:outputLabel id="lastnameLabel" for="lastname" value="Last Name: ">
                <h:inputText id="lastname" value="#{student.lastname}"/>
            </h:outputLabel>
            <br/>
            <br/>
            <h:commandButton
                    id="addStudentButton" value="Add New Student">
                <f:ajax event="click"
                        listener="#{studentTableBacking.addStudent(student)}"
                        execute="firstname lastname"
                        render="studentsTable"/>
            </h:commandButton>
        </h:form>
    </div>
</h:body>
</html>

fixajax.js
jsf.ajax.addOnEvent(function(data) {
    if (data.status == "success") {
        fixViewState(data.responseXML);
    }
});
 
function fixViewState(responseXML) {
    var viewState = getViewState(responseXML);
 
    if (viewState) {
        for (var i = 0; i < document.forms.length; i++) {
            var form = document.forms[i];
 
            if (form.method == "post") {
                if (!hasViewState(form)) {
                    createViewState(form, viewState);
                }
            }
            else { // PrimeFaces also adds them to GET forms!
                removeViewState(form);
            }
        }
    }
}
 
function getViewState(responseXML) {
    var updates = responseXML.getElementsByTagName("update");
 
    for (var i = 0; i < updates.length; i++) {
        var update = updates[i];
 
        if (update.getAttribute("id").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/)) {
            return update.textContent || update.innerText;
        }
    }
 
    return null;
}
 
function hasViewState(form) {
    for (var i = 0; i < form.elements.length; i++) {
        if (form.elements[i].name == "javax.faces.ViewState") {
            return true;
        }
    }
 
    return false;
}
 
function createViewState(form, viewState) {
    var hidden;
 
    try {
        hidden = document.createElement("<input name='javax.faces.ViewState'>"); // IE6-8.
    } catch(e) {
        hidden = document.createElement("input");
        hidden.setAttribute("name", "javax.faces.ViewState");
    }
 
    hidden.setAttribute("type", "hidden");
    hidden.setAttribute("value", viewState);
    hidden.setAttribute("autocomplete", "off");
    form.appendChild(hidden);
}
 
function removeViewState(form) {
    for (var i = 0; i < form.elements.length; i++) {
        var element = form.elements[i];
        if (element.name == "javax.faces.ViewState") {
            element.parentNode.removeChild(element);
        }
    }
}

fixAjax.js is from here.

In Action: