1

Problem:h:commandButton ajax not working with JSF bean, while page is loading.

A have JSF page with long list (takes couple seconds to load):

<?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://xmlns.jcp.org/jsf/html"
      xmlns:co="http://java.sun.com/jsf/composite/standart/components"> 

    <h:form id="myForm"> 
        <div><h:outputLabel value="My name is #{myViewBean.name}" /></div>
        <h:commandButton
            action="#{myViewBean.actRedirectToAnotherView()}" 
            value="Redirect"/>                
        <h:dataTable value="#{myViewBean.bigList}" var="entity">
            <h:column>
                #{entity}
            </h:column>
        </h:dataTable>
    </h:form>
</html>

And managed view scoped bean “MyViewBean”:

package mypackage;

import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;
import org.springframework.context.annotation.Scope;

@Named
@Scope(value = "view")
public class MyViewBean {

    private static int beanNrCounter = 0;
    private static final List<String> bigList = new ArrayList();
    static {
        for (int i = 0; i < 100000; i++) {
            bigList.add("Item in big list " + i);
        }
    }

    private final String name;

    public MyViewBean() {
        beanNrCounter++;
        name = "BEAN NR " + beanNrCounter;
        System.out.println("Created MyViewBean with name " + name);  
    }

    public String actRedirectToAnotherView() {
        String viewName = "anotherView.jsf";//actually some complex operation which decides where to redirect user 
        System.out.println("Redirecting to another view " + viewName );
        return viewName + "&faces-redirect=true";
    }

    public String getName() {
        return name;
    }

    public List<String> getBigList() {
        return bigList;
    }

}

If I click button "Redirect" while page is loading method “actRedirectToAnotherView” is not executed, but instead another “MyViewBean” bean is created. If I click button then page is already loaded, everything works as expected.

I have inspected, that then "Redirect" button is clicked, if page is loaded form parameter javax.faces.ViewState is passed with ajax post, but if page is loading - javax.faces.ViewState is missing (so off course new view is created).

If I change scope of managed bean to "request" problem stays ("Redirect" button is still not working, actRedirectToAnotherView is not executed).

How can I fix ajax behaviors while page is loading? It seems to me that javax.faces.ViewState is known on client side as soon as MyViewBean is accessed, so javax.faces.ViewState should be passed regardless if page is already loaded or not.

I am using:

Palladium
  • 280
  • 2
  • 15
  • 1
    Safest thing is to block the page while loading or load partsof the content of the page lazily (= different thing than e.g. lazy datatable) – Kukeltje Jan 20 '16 at 08:08
  • Probably Kukeltje both proposed solutions would work. Just blocking is not the most user friendly solution and lazy loading just make problem less noticeable (for really slow internet connection it still remains). For me looks strange that almost all jsf ajax based functionality would not work as expected while page is loading (easily noticeable with slow internet connection) – Palladium Jan 20 '16 at 08:24
  • Apart from the concrete problem, why are you using POST for navigation? Use ``. – BalusC Jan 20 '16 at 08:47
  • This is just prototype to show problem with minimal code. actRedirectToAnotherView method performs some "business logic", and "decides" where to redirect user. I will update code example to make it "logical". – Palladium Jan 20 '16 at 08:50
  • 1
    OK. Must it really be in the same form as the table? There doesn't seem to be any inputs in the table relevant to the request. Otherwise simply put button in its own form. You know, one
    per form.
    – BalusC Jan 20 '16 at 08:56
  • In “real” application my button is in table. But I can create form in every line of data table (and that solution works). So it looks like submit is not working correctly while all form elements are not loaded. So to eliminate this problem should probably I should refactor my forms to eliminate any unnecessary elements, or perform partial submit if form fields are not needed. – Palladium Jan 20 '16 at 09:15
  • My mistake in previous comment, partial submit is not helping - while all form is not loaded, actions are not working. – Palladium Jan 20 '16 at 09:33

1 Answers1

-2

look at this Example I hope you find it useful

Facelets:

<h:form>
    <h:commandLink value="show" action="#{showProducts.toggleShow}">
        <f:ajax render="products"/>
    </h:commandLink>
    <h:panelGroup id="products">
        <h:dataTable var="product" value="#{showProducts.products}" rendered="#{!showProducts.show}">
            <h:column>#{product.name}</h:column>
        </h:dataTable>
    </h:panelGroup>
</h:form>

and for Managed Bean

private List<Product> products;

@PostConstruct
public void init() {
    products = this.getProductManager().getProducts();
}

public List<Product> getProducts() {
    return products;
}
Or if it actually needs to be lazily loaded, then rather do so:

private List<Product> products;

public List<Product> getProducts() {
    if (products == null) {
        products = this.getProductManager().getProducts();
    }
    return products;
}
  • 1
    I am not sure how can it help in my situation (I am, not doing any expensive operations in getters, my list is static and loaded one time during application startup). Problem is with javax.faces.ViewState which is not passed while page is loading (page is ~7Mb so naturaly takes couple of seconds) – Palladium Jan 20 '16 at 07:36