1
votes

The scenario: I want to partially execute and render part of a form in JSF, using AJAX, through the use of a commandLink. Since this will be done through AJAX, from my understanding ViewScoped should hold the values of the components in the page between AJAX requests.

I created an example below, where I have an input box where an Order Name is entered, the commandLink is pressed (labeled "Enter Order"), the order name from the inputText is added to an ArrayList named "orders", and the "orders" are displayed in a DataTable below the CommandLink.

The AJAX request from the CommandLink executes the inputBox that adds the String value to the "orderName" variable. The AJAX request sends an ActionEvent to the processDataTable() method, that takes the "orderName" value and adds it to the "orders" list. The "orderName" is then nulled. The AJAX request then renders the inputText component with the nulled "orderName", and the DataTable that displays all the previously entered orders, including the newly added "orderName" from this request.

Problem: The code works if I'm using a SessionScoped bean, but NOT if I use a ViewScoped bean. I added System.out.println()'s to the code to see what was happening. If I make the bean SessionScoped, then everything works as planned. The inputText value is set through the set method, the processOrder() method adds the "orderName" String to the "orders" List, and the DataTable is re-rendered to show this added name. ...

With a ViewScoped bean, the "orderName" value is set to the value of the InputText Component, but is "null" inside of the ProcessOrder() method, adds "null" to the "orders" List, and the DataTable has nothing to show besides null.

If I manually add an orderName in processOrder() with orders.add("Some Name") before the "orderName" is added, "orders" will then hold {"Some Order", "null"} and the change to the Orders is still NOT re-rendered with the AJAX.

All works great with a SessionScoped bean and NOT with a ViewScoped bean? I have also tried an Action attribute with the CommandLink instead of the ActionListener, and the same story.. works with SessionScoped but NOT with ViewScoped.

I can only think of two things here, 1) Either I am missing a crucial point in how AJAX and CommandLink work together, and how ViewScoped is supposed to work (very possible); or 2) for some reason, how I submit the AJAX call with CommandLink it is refreshing the page each time it is clicked, thus erasing previous values of the "orders" list. However this still does not explain why if I manually enter an order into the List, it is still not rendered in the AJAX request with a ViewScoped bean, but WILL with a SessionScoped bean.

Help please!!??

Here's my code:

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

@Named(value = "testBean")
@ViewScoped
public class DataTableTest implements Serializable {

  private String orderName;
  private List<String> orders = new ArrayList<String>();

  public DataTableTest () {}

  public String getOrderName() {
    return orderName;
  }

  public void setOrderName(String orderName) {
    this.orderName = orderName;
    System.out.println(orderName + " in setOrderName");
  }

  public List<String> getOrders() {
    return orders;
  }

  public String processDataTable(ActionEvent event) {
    System.out.println(orderName + " before getting added to orders list in     processDataTable");
    orders.add(orderName);      // adds the orderName to the orders list, so it can be     viewed in the DataTable
    orderName = null;           // nulling variable so it displays BLANK once again on      the form

    // Loops through and displays order names in the orders list
    for (String name : orders) {
      System.out.println(name + " in orders List");
    }
    return null;
  }
}

and here's my jsf page:

<?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">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

  <h:head>
    <title>Test</title>
  </h:head>
  <h:body>
    <h:form>
      <h:panelGrid columns="3">
        <h:outputText value="Enter Order Name >>" />
        <h:inputText id="orderName" value="#{testBean.orderName}" label="#    {testBean.orderName}" />
        <h:message for="orderName" />
      </h:panelGrid>
      <h:commandLink value="Enter Order" actionListener="#{testBean.processDataTable}">
        <f:ajax execute="orderName dataTable" render="orderName dataTable" />
      </h:commandLink>
      <h:dataTable id="dataTable" value="#{testBean.orders}" var="order">
        <f:facet name="header">Orders Entered Shown Below: </f:facet>
        <h:column>
          <h:outputText value="#{order}" />
        </h:column>
      </h:dataTable>
    </h:form>
  </h:body>
</html>
1

1 Answers

2
votes

You are using an CDI-Bean, but the @ViewScoped-Annotation, that you are using, is JSF-specific and does not work in a CDI-Bean.

You could use a JSF-managedBean instead

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name="testBean")
@ViewScoped
public class DataTableTest implements Serializable { .. }

If changing to a managedBean is not an option for you, take a look at CDI-specific @ConversationScope or Seam, where you have a @ViewScoped annotation that also works fine with CDI-Beans.