【问题标题】:JSF2 "f:ajax render" renders more than the specified idJSF2 "f:ajax render" 渲染超过指定的 id
【发布时间】:2011-09-29 16:49:48
【问题描述】:

我在这里和网络上搜索并尝试了各种东西; prependId,使用完整的 id 路径(:form:panelid:componentid 有点像)等。

我还是一头雾水。我还是个 JSF 菜鸟 :)

我的问题是,我在 f:ajax 渲染部分中指定的内容并不是 唯一 被“执行”的部分。我的意思是,在 render 中指定的 id 不会在屏幕上重新渲染,但该组件的值会被调用。

所以:

inputText 的 f:ajax render=outA event=blur

当模糊发生时,outA 的 getter 被调用并重新渲染,但其他组件的 getter 也被调用,但它们不被重新渲染。

具体来说,根据下面列出的代码:

A) 当 val1 失去焦点时,会触发 blur 事件,它会调用 getValue1() 并重新渲染 outval1。快乐的。但是,getStuff() 也被调用(它也发生在其他模糊和 btnCalc 中)但是 getStuff() 的结果不会呈现到 tblStuff dataTable。 为什么?

我该如何解决它,以便在 blur 事件中,只执行与 render=".." 组件相关的 getter?

我应该使用不同的部分吗?

B) 当单击刷新按钮时,它会再次调用 getStuff,现在显示新的 dataTable / 即在模糊事件和 btnReload 单击事件期间添加的所有 ValueTO 的新数据。

C) 对于在 A 中命名的任何一个事件,getStuff 方法被准确地调用了 8 次。即点击输入框内,点击输入框外,getStuff() * 8。 然而,getValue1 只被调用了两次?

D) 有什么好的 JSF2 书籍吗?

这是页面:

<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">

<h:head>
    <title>Stuff</title>
</h:head>
<h:body>
        <h:form id="frmTrxMain" prependId="true">

            <h1>
                Stuff
            </h1>

            <h:dataTable title="Stuff" id="tblStuff" var="s" value="#{bean.stuff}" border="1">

                <h:column>
                    <f:facet name="header">
                        <h:outputText value="ID" />
                    </f:facet>
                    <h:outputText value="#{s.id}"/>
                </h:column>

                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Name" />
                    </f:facet>
                    <h:outputText value="#{s.name}" />
                </h:column>

            </h:dataTable>

            <h:outputText value="No stuff to display" rendered="#{empty bean.stuff}"/>
            <h:commandButton value="Refresh" id="btnReload">
                <f:ajax render="tblStuff" event="click"/>
            </h:commandButton>

            <hr/>

            <h:panelGrid columns="3" id="pnlTwo">
                <h:outputLabel value="Value1"/>
                <h:inputText value="#{bean.value1}" id="val1">
                    <f:ajax event="blur" render="outVal1"/>
                </h:inputText>
                <h:outputText id="outVal1" value="Entered: #{bean.value1}" />

                <h:outputLabel value="Value2"/>
                <h:inputText value="#{bean.value2}" id="val2">
                    <f:ajax event="blur" render="outVal2"/>
                </h:inputText>
                <h:outputText id="outVal2" value="Entered: #{bean.value2}" />

                <h:commandButton value="Calc" id="btnCalc"> 
                  <f:ajax event="click" render="outSum"/> 
                </h:commandButton> 
            </h:panelGrid>

            <h:outputLabel id="outSum" value="#{bean.sum}"/>
        </h:form>
</h:body>
</html>

还有后台bean:

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name = "bean")
@SessionScoped
public class TestStuffBean {

private int id=1;
private String name="a";
//test.xhtml
private String value1;
private String value2;

private List<TestVO> stuff = new ArrayList<TestVO>();

public String getValue1() {
    return value1;
}

public void setValue1(String value1) {
    this.value1 = value1;
}

public String getValue2() {
    return value2;
}

public void setValue2(String value2) {
    this.value2 = value2;
}

public String getSum() {

    String result = "";

    int sum;
        try {
            sum = Integer.parseInt(value1) + Integer.parseInt(value2);
            result = Integer.toString(sum);
        } catch (NumberFormatException e) {
            result = "Enter two integers";
        }

    return result;
}

public List<TestVO> getStuff() {
    //the VO is just a POJO with a contructor that takes 
            //two strings and a getter/setter for each id and name
        stuff.add(new TestVO(Integer.toString(id), name+id));
        id++;

    return stuff;
}
}

【问题讨论】:

    标签: java ajax jsf jsf-2 render


    【解决方案1】:

    我不是 JSF 2 专家,因为我们仍在使用 1.2,但我猜它们在这里具有相同的属性:经常调用 getter,例如在恢复视图阶段重建视图时。因此,您不能仅依赖于实际渲染部分调用 getter。事实上,您不应该在您的 getter 中执行任何代价高昂的操作(如 db 访问)——在大多数情况下,您不知道它们在一个周期中实际调用的频率。

    尤其是你的 getStuff() 方法应该改变,它也几乎总是糟糕的设计,让 getter 导致副作用,比如将某些东西添加到内部列表中,就像在这种情况下。

    编辑:澄清对吸气剂的评论:

    通常,getter 不应该执行昂贵的操作,因为您不知道 JSF 多久调用一次。 由于您仍然需要从某个源(例如数据库)获取一些数据,您可能会提供仅执行此操作的方法(例如 loadDataFromDB())并在托管 bean 中填充一些数据结构。然后,getter 可能只提供该数据结构。

    您可以添加一个未初始化数据结构的检查,如果未在 getter 中调用 load 方法,但我只会将其用作最后一个选项。一般来说,您应该能够单独调用加载方法,例如通过单击刷新按钮或导航到页面时 - 这就是我们所做的。

    【讨论】:

    • 同意。为了这个问题,我简化了实际代码。这里添加到集合是一个不好的例子,它会从数据库中获取数据,将其存储在这个 bean(会话)上并设置一个标志,表明它有数据;然后将检查随后的 getStuff() 调用,从而避免多个负载。 Refresh 按钮可以有一个侦听器,该侦听器将该标志设置回 false,这意味着将在下一次获取时获取数据。不确定这是否真的更好,但我一直在寻找更好地编写 JSF 代码的方法...... :)
    • 也许我对 AJAX 的作用有一个不正确的想法:发生了一个事件(btn 点击),异步获取一个值(通过 getter)并重新渲染/更新特定字段(标签)。其他一切都保持不变。然而,在这种情况下,所有字段都有其 getter/setter 执行,但只有标签被更新/呈现。嗯..
    • 好吧,AJAX 只是更新 UI 的一部分,但为了做到这一点,JSF 必须调用一堆 getter 并重建至少部分组件树。这就是为什么即使对于非重新渲染的组件也会调用 getter 的原因。 - 至于查询数据库的getter:我会更新我的答案。
    • 啊,“至少重建组件树的一部分”对我来说很有意义。 wrt更新,这正是我在某一时刻所拥有的,但在某个地方我搞砸了事物的状态,什么时候应该重新加载,什么时候不;困惑。谢谢托马斯
    猜你喜欢
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 2011-10-14
    • 2011-04-02
    • 2012-05-27
    • 2011-08-22
    • 1970-01-01
    • 2012-10-30
    相关资源
    最近更新 更多