views:

153

answers:

2

I have a problem with f:ajax tag. In my previous project, everything worked perfectly. Now I have another project and f:ajax tag doesn't work at all and I don't know why.

I have this in JSF page with Facelets:

<h:form>
...
    <h:selectOneMenu id="employeeId" value="#{employeeBean.employeeId}">
        <f:selectItems value="#{employeeBean.employeesSelectItem}"/>
        <f:ajax event="change" listener="#{employeeBean.changeOwner}"/>
     </h:selectOneMenu>
...
</h:form>

And employeeBean with changeOwner method with database access:

...
public void changeOwner(AjaxBehaviorEvent event) {
    try {
        update.updateOwner(...params...);
        JSF.setMessage(Messages.UPDATE_OK);
    } catch (UpdateDBException ex) {
        JSF.setMessage(ex.getMessage());
    }
}
...

I can't see anything wrong. Thanks for help.

UPDATE

faces-config:

<faces-config version="2.0"
    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-facesconfig_2_0.xsd"&gt;

    <converter>
        <converter-for-class>java.util.Date</converter-for-class>
        <converter-class>misc.TimeZoneConverter</converter-class>
    </converter>
</faces-config>

xhtml page:

<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
            template="./../templates/mainTemplate.xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:f="http://java.sun.com/jsf/core"&gt;

<ui:define name="content">
    <h2>Smazání zaměstnance</h2>
            Protože s daným zaměstnancem (#{employeeBean.employee.name} #{employeeBean.employee.surname}) souvisejí některé úkoly, je potřeba, aby se jich ujal jiný. Vyberte prosím nové zaměstnance u všech níže uvedených úkolů.
            <h:form>
                <h:dataTable value="#{taskBean.employeeTasks}" var="item">
                    <h:column>
                        <f:facet name="header">ID</f:facet>
                        <center>#{item.idtask}</center>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Zadavatel</f:facet>
                        <h:selectOneMenu id="managerId" value="#{employeeBean.newManagerId}" rendered="#{employeeBean.employeeId == item.employeeByIdmanager.idemployee}">
                            <f:selectItems value="#{employeeBean.otherEmployeesSelectItem}"/>
                            <f:ajax event="change" listener="#{employeeBean.changeOwner}"/>
                        </h:selectOneMenu>
                        <h:outputText value="#{item.employeeByIdmanager.name} #{item.employeeByIdmanager.surname}" rendered="#{employeeBean.employeeId != item.employeeByIdmanager.idemployee}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Zodpovědná osoba</f:facet>
                        <h:selectOneMenu id="employeeId" value="#{employeeBean.newEmployeeId}" rendered="#{employeeBean.employeeId == item.employeeByIdemployee.idemployee}">
                            <f:selectItems value="#{employeeBean.otherEmployeesSelectItem}"/>
                            <f:ajax event="change" listener="#{employeeBean.changeOwner}"/>
                        </h:selectOneMenu>
                        <h:outputText value="#{item.employeeByIdemployee.name} #{item.employeeByIdemployee.surname}" rendered="#{employeeBean.employeeId != item.employeeByIdemployee.idemployee}"/>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Čas zadání</f:facet>
                        <center><h:outputText value="#{item.timestart}"/></center>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Udělat do</f:facet>
                        <center><h:outputText value="#{item.timetodo}"/></center>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Popis úkolu</f:facet>
                        #{item.text}
                    </h:column>
                    <h:column>
                        <f:facet name="header">Zákazník</f:facet>
                        <h:link outcome="viewCustomerDetails">
                            <h:panelGrid columns="1">
                                <h:outputText value="#{item.customer.name}"/>
                                <h:outputText value="#{item.customer.addresscity}"/>
                            </h:panelGrid>
                            <f:param name="customerId" value="#{item.customer.idcustomer}"/>
                        </h:link>
                    </h:column>
                    <h:column>
                        <f:facet name="header">Stav úkolu</f:facet>
                        #{item.taskstate.state}
                    </h:column>
                    <h:column>
                        <f:facet name="header">Poznámky</f:facet>
                        <h:outputText escape="false" value="#{item.note}"/>
                    </h:column>
                </h:dataTable>
            </h:form>

    <h:messages globalOnly="true" styleClass="messages"/>
</ui:define>

UPDATE2

EmployeeBean:

package beans;
import beans.jsf.JSF;
import ejb.Get;
import ejb.Update;
import entities.Employee;
import entities.Permission;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.model.SelectItem;
import javax.validation.constraints.Pattern;
import misc.Messages;

@ManagedBean(name="employeeBean")
@RequestScoped
public class EmployeeBean {

@EJB
private Get get;

@EJB
private Update update;

@ManagedProperty(name="employeeId", value="#{param['employeeId']}")
private int employeeId;

private int newManagerId;

private int newEmployeeId;

private String edit = "none";

@Pattern(regexp=".+", message="Jméno musí být vyplněno.")
private String name;

@Pattern(regexp=".+", message="Příjmení musí být vyplněno.")
private String surname;

private int permissionId;

private Employee employee;

/** Creates a new instance of EmployeeBean */
public EmployeeBean() {
}

public int getNewEmployeeId() {
    return newEmployeeId;
}

public void setNewEmployeeId(int newEmployeeId) {
    this.newEmployeeId = newEmployeeId;
}

public int getNewManagerId() {
    return newManagerId;
}

public void setNewManagerId(int newManagerId) {
    this.newManagerId = newManagerId;
}

public int getEmployeeId() {
    return employeeId;
}

public void setEmployeeId(int employeeId) {
    this.employeeId = employeeId;
    employee = get.getEmployee(employeeId);
}

public String getEdit() {
    return edit;
}

public void setEdit(String edit) {
    this.edit = edit;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getPermissionId() {
    return permissionId;
}

public void setPermissionId(int permissionId) {
    this.permissionId = permissionId;
}

public String getSurname() {
    return surname;
}

public void setSurname(String surname) {
    this.surname = surname;
}

public Employee getEmployee() {
    return employee;
}

public void setEmployee(Employee employee) {
    this.employee = employee;
}

private void showEdit() {
    edit = "block";
}

private void hideEdit() {
    edit = "none";
}

/**
 * Naplní SelectItem všemi zaměstnanci.
 * @return seznam zaměstnanců
 */
public List<SelectItem> getEmployeesSelectItem() {
    List<SelectItem> employees = new ArrayList<SelectItem>();

    for (Employee e : get.getEmployees()) {
        employees.add(new SelectItem(e.getIdemployee(), e.getName() + " " + e.getSurname()));
    }

    return employees;
}

/**
 * Vrátí seznam zákazníků.
 * @return seznam zákazníků
 */
public List<Employee> getEmployees() {
    return get.getEmployees();
}


/**
 * Načte úkol pro editaci.
 */
public void loadEmployee() {
    Employee e = get.getEmployee(employeeId);

    if (e != null) {
        name = e.getName();
        surname = e.getSurname();
        permissionId = e.getPermission().getIdpermission();

        showEdit();
    } else {
        JSF.setMessage(Messages.DB_RETURN_NULL);
    }
}

/**
 * Naplní SelectItem všemi oprávněními.
 * @return seznam oprávnění
 */
public List<SelectItem> getPermissionsSelectItem() {
    List<SelectItem> permissions = new ArrayList<SelectItem>();

    for (Permission p : get.getPermissions()) {
        permissions.add(new SelectItem(p.getIdpermission(), p.getPermissionname()));
    }

    return permissions;
}    

/**
 * Zapíše úpravy úkolu.
 */
public void updateEmployee() {
    try {
        update.updateEmployee(name, surname, employeeId, permissionId);
        JSF.setMessage(Messages.EMPLOYEE_UPDATE_OK);
    } catch (Exception ex) {
        showEdit();
        JSF.setMessage(ex.getMessage());
    } 
}

/**
 * Zruší prováděné úpravy a skryje editaci.
 */
public void cancel() {
    hideEdit();
}

public void changeOwner(int taskId) {
    System.out.println("taskId: "+taskId);
    System.out.println("managerId: "+newManagerId);
    System.out.println("employeeId: "+newEmployeeId);
//        try {
//            update.updateOwner(taskId, newManagerId, newEmployeeId);
//            JSF.setMessage(Messages.UPDATE_OK);
//        } catch (UpdateDBException ex) {
//            JSF.setMessage(ex.getMessage());
//        }
}

/**
 * Naplní SelectItem všemi možnými stavy pro úkol.
 * @return seznam stavů úkolu
 */
public List<SelectItem> getOtherEmployeesSelectItem() {
    List<SelectItem> employees = new ArrayList<SelectItem>();

    for (Employee e : get.getOtherEmployees(employeeId)) {
        employees.add(new SelectItem(e.getIdemployee(), e.getName() + " " + e.getSurname()));
    }

    return employees;
}
}
A: 

Since f:ajax listener expects to AjaxBehaviorEvent

change it to:

public void changeOwner(AjaxBehaviorEvent event) {
    try {
        update.updateOwner(...params...);
        JSF.setMessage(Messages.UPDATE_OK);
    } catch (UpdateDBException ex) {
        JSF.setMessage(ex.getMessage());
    }
}

EDITED: Check if any other component in the form blocks the form from being submitted. (Maybe h:selectonemenu etc.)

Odelya
That is an optional argument. If both methods are present, the one without the argument will be invoked btw.
BalusC
@BalucC - not according to: http://download-llnw.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/f/ajax.html see the documentation for listener attribute:javax.el.MethodExpression (signature must match public void processAjaxBehavior(javax.faces.event.AjaxBehaviorEvent event) throws javax.faces.event.AbortProcessingException)
Odelya
It worked without the parameter for me in the past. Nevertheless, this change didn't make any difference.
Tom
@Odelya: JSF has a lot of undocumented features :) But you're right that you *should* add the agrument. You don't want to be dependent on the implementation.
BalusC
@Tom: do you have other components in the form? maybe they are not configured properly and the form cannot be submitted
Odelya
I posted here the whole page and the faces-config. But I can't see anything wrong...
Tom
I just want to set a new employee to a task when the selectOneMenu changes...
Tom
@Tom: newEmployeeId and newManagerId are of the same type of the SelectItem(id,name) id? I mean, if you put in SelectItem id of type long, also in the bean newEmployeeId is of type long?
Odelya
@Odelya: I have id of the type int, both of them (just as it is in the bean). I did a few JSF projects before and I didn't have basic problems. And just as I said, this ajax feature works well in my other project and even if there is no difference between them, this just doesn't work...
Tom
A: 

This will only work when the input element is inside a form. So put the whole menu in a <h:form>.


Update: the f:ajax is in fact a JSF 2.0 tag. If you ever change your JSF libs or the faces-config.xml to comply JSF 1.2, then the f:ajax will stop working. Verify if you're using the correct versioned libs and the root declaration of any faces-config.xml is set to JSF 2.0.

If that doesn't help, then I don't see other causes than that you aren't running the code you think you're running. Did you read the server logs? Did you run the debugger? Did you eliminate the surrounding code so that the JSF page ends up with only the code as in your question inside the h:body?


Update 2: the EmployeeBean is set as @RequestScoped which means that it's garbaged at end of request (after sending the response). The loading of the employee is depending on the presence of an employee ID which is been set as a request parameter. Basically you need to pass the employee ID on every request to get the employee to load, including ajaxical requests. Also, the rendering of the dropdown is depending on the presence of a valid employee in the request. If the rendered condition evaluates false during ajaxical request, the ajax action won't be invoked. I am not sure about this complex case, but in theory passing the employee ID as hidden parameter should help:

<h:inputHidden value="#{employeeBean.employeeId}" />

Put it in the form next to the table.

BalusC
I have it in a form. I forgot to post it here. Now it's changed...
Tom
Server logs ale clean, debugger shows nothing. It looks like the bean method isn't called. But why?
Tom
Does the other dropdown in the same table work? Does it work when you put the whole form+dropdown alone in its own file?
BalusC
If I put the dropdown alone in the page, it works. But if I put it into the table, i doesnt work... Why is that?
Tom
You need to preserve the data. Make the bean `@ViewScoped`.
BalusC
When I change the scope, I get this error: javax.servlet.ServletException: Unable to create managed bean employeeBean. The following problems were found: - The scope of the object referenced by expression #{param[employeeId]}, request, is shorter than the referring managed beans (employeeBean) scope of view.I pasted the whole EmployeeBean above.
Tom
@Update 2: The employee is loaded correctly, even without this hidden field. But I added it anyway and it made no difference. Maybe the ViewScoped bean could help, but I've never used this scope and I don't know how to solve the error. The employeeId property has to be managed or it won't load the value from the parameter.
Tom
How about the `#{taskBean}`? Does it preserve the same data in the subsequent requests?
BalusC
Only employeeId is in the both of them. Everything else is different. Data from the taskBean are read directly from db.
Tom