【问题标题】:JSF app, actions don't work if a different action has been invoked previouslyJSF 应用程序,如果之前调用了不同的操作,则操作将不起作用
【发布时间】:2011-06-25 13:41:52
【问题描述】:

我正在 JBoss6 上学习 Java EE 6 和 JSF 2.0,并构建了一个非常简单的单页“Todo”应用程序,该应用程序可以运行,但有一个非常奇怪的错误。在 Safari 5.0.5 和 Firefox 5 中测试。

您可以执行两种操作(添加待办事项和选中/取消选中待办事项)。这一切都有效,但不是第一次在完成不同的操作后完成一个操作。

示例用法可能如下所示:

  1. 尝试添加待办事项 = 成功
  2. 尝试添加待办事项 = 成功
  3. 尝试检查待办事项 = 失败
  4. 尝试检查待办事项 = 成功
  5. 尝试添加待办事项 = 失败
  6. 尝试添加待办事项 = 成功
  7. 尝试检查待办事项 = 失败

该应用程序具有以下基本文件(以及其他零碎):

  • entities/Todo.java
  • managers/TodoManager.java
  • controllers/TodoController.java
  • todos.xhtml

没有 faces-config.xml

添加待办事项的表单如下所示:

<h:panelGroup id="projects">
   <h:message for="newtitle" />
   <h:form id="newtodo">
    <h:panelGrid columns="5">
            <h:outputText value="New Todo: "/>
            <h:inputText id="newtitle" value="#{todoController.todo.title}" />
            <h:outputText value="Due: "/>
            <h:inputText id="newDueDate" value="#{todoController.todo.dueDate}">
                <f:convertDateTime pattern="dd/mm/yyyy"/>
            </h:inputText>
            <h:commandButton action="#{todoController.addTodo}" value="add">
                <f:ajax execute="@form" render=":projects"/>
            </h:commandButton>

检查/取消选中待办事项“完成”状态的表单如下所示:

<h:form>
    <h:dataTable id="todolist" var="t" value="#{todoController.todolist}">
        <h:column>
            <h:selectBooleanCheckbox id="rowCheckbox" value="#{t.done}" >
                <f:ajax event="click" listener="#{todoController.updateDone(t)}" render=":projects"/>
            </h:selectBooleanCheckbox>
        </h:column>

TodoController 看起来像这样:

@ManagedBean(name="todoController")
@SessionScoped
public class TodoController 
{
    @EJB
    private TodoManager todoManager;
    private Todo todo = new Todo();
    private ArrayList<Todo> todolist = new ArrayList<Todo>();

    public String addTodo()
    {
        todo.setDone(false);
        todo.setUser(this.getLoggedInUser());
        todoManager.addTodo(todo);
        todo = null;
        return "todos.xhtml";
    }

    public String updateDone(Todo t)
    {
        t.setDone(!t.getDone());
        todoManager.updateTodo(t);
        return "todos.xhtml";
    }

我确实将日志消息添加到 addTodo() 和 updateDone(Todo t) 以验证它们何时被调用。当动作“不起作用”时,它们实际上似乎根本没有被调用。 :-(

【问题讨论】:

  • 发现如果我在预期会失败的操作之前刷新页面,它会起作用。虽然有点违背 AJAX 的目的:-(

标签: java jsf-2 jboss6.x


【解决方案1】:

当您有 2 个表单时会发生这种情况,其中第二个表单是通过合并第一个表单来重新呈现的。这样,第二种形式的 JSF 视图状态将完全丢失(您可以通过在 Ajax 响应中缺少名称为 javax.faces.ViewState 的隐藏输入字段来自行确定)。在通过第一个表单的提交重新呈现后提交第二个表单将在视觉上没有效果。如果没有视图状态,JSF 将不会处理表单的提交。只有一个新表单(具有正确的视图状态!)会恢复原状,因此第二次提交有效。

您需要微调render 属性,以便仅重新呈现第二个表单的内容而不是整个表单本身。

例如

<h:form id="form1">
    <h:panelGroup id="content">
        ...
        <h:commandButton value="Submit">
            <f:ajax execute="@form" render="@form :form2:content" />
        </h:commandButton>
    </h:panelGroup>
</h:form>
<h:form id="form2">
    <h:panelGroup id="content">
        ...
        <h:commandButton value="Submit">
            <f:ajax execute="@form" render="@form :form1:content" />
        </h:commandButton>
    </h:panelGroup>
</h:form>

在您的特定情况下,给第一个表单的&lt;h:panelGrid&gt; 和第二个表单的&lt;h:dataTable&gt; 一个固定的id,然后从另一个表单开始重新渲染。

【讨论】:

  • 对,所以如果您有多个带有 AJAX 调用的表单,那么您不应该只重新渲染
    组件本身,而只渲染子组件。
  • 仅当它是您要提交的另一个时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 2016-02-24
相关资源
最近更新 更多