I have a @ViewScoped
@ManagedBean
which creates an unique ID. This ID is rendered in a form like:
我有一个@ViewScoped @ManagedBean,它创建一个唯一的ID。此ID以以下形式呈现:
<h:form>
<h:outputText value="#{myBean.uid}" id="uid"/>
<h:hiddenInput value="#{myBean.uid}" id="hiddenId" />
....
<p:commandButton actionListener="#{myBean.create}" ajax="true" update="@form" value="Create" />
</h:form>
So far so good. On first request the page is rendered correctly. After submitting the form and in the case of validation failure, the outputText
is empty but the hidden input field keeps its variable. Any clue what I'd have to do to prevent this behavior and too let the outputText
keep its state? I realized that the bean seems to be initialized after each ajax request. But then, why does the hidden input field keeps the old variable?
到现在为止还挺好。在第一次请求时,页面正确呈现。提交表单后,如果验证失败,则outputText为空,但隐藏的输入字段保留其变量。任何线索我必须做什么来防止这种行为,并让outputText保持其状态?我意识到在每次ajax请求之后,bean似乎都被初始化了。但是,为什么隐藏的输入字段会保留旧变量?
Here is the relevant code of my bean:
这是我的bean的相关代码:
@ManagedBean(name = "myBean", eager = true)
@Stateful
@Model
@ViewScoped
public class MyBean implements Serializable {
...
private String uid;
...
@PostConstruct
public void initWithData() {
this.uid = UUID.randomUUID().toString();
}
}
2 个解决方案
#1
3
JSF input components have 3 places where the value (the state) is stored:
JSF输入组件有3个存储值(状态)的位置:
-
Submitted value (the raw unconverted/unvalidated
String
request parameter value). - Local value (the successfully converted/validated object value, stored inside component itself).
- Model value (when the entire form is successfully processed, stored as bean property)
提交的值(原始未转换/未验证的String请求参数值)。
本地值(成功转换/验证的对象值,存储在组件本身内)。
模型值(成功处理整个表单时,存储为bean属性)
JSF processes input components as follows:
JSF按如下方式处理输入组件:
- Get HTTP request parameter value by component's client ID and store it as submitted value.
- If conversion/validation succeeds, set it as local value and set submitted value to
null
. - If entire form is successfully processed, set it as model value and set local value to
null
.
按组件的客户端ID获取HTTP请求参数值,并将其存储为提交的值。
如果转换/验证成功,请将其设置为本地值并将提交的值设置为null。
如果成功处理整个表单,请将其设置为模型值并将本地值设置为null。
JSF renders values of input components as follows:
JSF呈现输入组件的值,如下所示:
- If submitted value is not
null
, display it. - Else if local value is not
null
, display it. - Else display model value.
如果提交的值不为null,则显示它。
否则,如果本地值不为null,则显示它。
否则显示模型值。
So, in your particular case of a general validation failure, JSF is for that hidden input component just redisplaying the local value instead of the model value. If you want to achieve the same with the output text, I think best is to just do the same as JSF:
因此,在一般验证失败的特定情况下,JSF用于隐藏的输入组件,只是重新显示本地值而不是模型值。如果你想在输出文本中实现相同的功能,我认为最好是和JSF一样:
<h:outputText value="#{empty hiddenId.submittedValue ? empty hiddenId.localValue ? hiddenId.value : hiddenId.localValue : hiddenId.submittedValue}" />
<h:inputHidden id="hiddenId" binding="#{hiddenId}" value="#{myBean.uid}" />
Alternatively, you could just use a read only input and remove the border by CSS if necessary:
或者,您可以只使用只读输入,并在必要时通过CSS删除边框:
<h:inputText id="hiddenId" value="#{myBean.uid}" readonly="true" style="border: none;" />
As to your bean, I'm not sure what's happening there as this class seems to be extremely tight coupled. I'd rather split it into 3 classes: one real backing bean, one stateless service and one model entity. Further, you should also make sure that you aren't binding view build time tags or attributes to a property of a view scoped bean. Otherwise it will indeed guaranteed be reconstructed on every single request.
至于你的bean,我不确定那里发生了什么,因为这个类看起来非常紧密。我宁愿把它分成3个类:一个真正的支持bean,一个无状态服务和一个模型实体。此外,还应确保未将视图构建时标记或属性绑定到视图范围bean的属性。否则,它确实可以保证在每一个请求上重建。
See also:
- JSTL in JSF2 Facelets... makes sense?
- @PostConstruct method is called even if the ManagedBean has already been instantiated (e.g. on AJAX-calls)
JSF2 Facelets中的JSTL有意义吗?
即使ManagedBean已经被实例化(例如,在AJAX调用上),也会调用@PostConstruct方法
By the way, the eager=true
has only effect in @ApplicationScoped
beans.
顺便说一句,eager = true只对@ApplicationScoped bean有效。
#2
1
The problem is probably the @Model
stereotype (was, as you already removed it). It combines @Named
and @RequestScoped
and makes the bean a CDI request scoped bean. CDI managed beans should be resolved before JSF managed beans and therefore the @ViewScoped
has no effect (it creates a JSF managed bean).
问题可能是@Model构造型(就像你已经删除它一样)。它结合了@Named和@RequestScoped,并使bean成为CDI请求范围的bean。应该在JSF托管bean之前解析CDI托管bean,因此@ViewScoped没有效果(它创建了一个JSF托管bean)。
#1
3
JSF input components have 3 places where the value (the state) is stored:
JSF输入组件有3个存储值(状态)的位置:
-
Submitted value (the raw unconverted/unvalidated
String
request parameter value). - Local value (the successfully converted/validated object value, stored inside component itself).
- Model value (when the entire form is successfully processed, stored as bean property)
提交的值(原始未转换/未验证的String请求参数值)。
本地值(成功转换/验证的对象值,存储在组件本身内)。
模型值(成功处理整个表单时,存储为bean属性)
JSF processes input components as follows:
JSF按如下方式处理输入组件:
- Get HTTP request parameter value by component's client ID and store it as submitted value.
- If conversion/validation succeeds, set it as local value and set submitted value to
null
. - If entire form is successfully processed, set it as model value and set local value to
null
.
按组件的客户端ID获取HTTP请求参数值,并将其存储为提交的值。
如果转换/验证成功,请将其设置为本地值并将提交的值设置为null。
如果成功处理整个表单,请将其设置为模型值并将本地值设置为null。
JSF renders values of input components as follows:
JSF呈现输入组件的值,如下所示:
- If submitted value is not
null
, display it. - Else if local value is not
null
, display it. - Else display model value.
如果提交的值不为null,则显示它。
否则,如果本地值不为null,则显示它。
否则显示模型值。
So, in your particular case of a general validation failure, JSF is for that hidden input component just redisplaying the local value instead of the model value. If you want to achieve the same with the output text, I think best is to just do the same as JSF:
因此,在一般验证失败的特定情况下,JSF用于隐藏的输入组件,只是重新显示本地值而不是模型值。如果你想在输出文本中实现相同的功能,我认为最好是和JSF一样:
<h:outputText value="#{empty hiddenId.submittedValue ? empty hiddenId.localValue ? hiddenId.value : hiddenId.localValue : hiddenId.submittedValue}" />
<h:inputHidden id="hiddenId" binding="#{hiddenId}" value="#{myBean.uid}" />
Alternatively, you could just use a read only input and remove the border by CSS if necessary:
或者,您可以只使用只读输入,并在必要时通过CSS删除边框:
<h:inputText id="hiddenId" value="#{myBean.uid}" readonly="true" style="border: none;" />
As to your bean, I'm not sure what's happening there as this class seems to be extremely tight coupled. I'd rather split it into 3 classes: one real backing bean, one stateless service and one model entity. Further, you should also make sure that you aren't binding view build time tags or attributes to a property of a view scoped bean. Otherwise it will indeed guaranteed be reconstructed on every single request.
至于你的bean,我不确定那里发生了什么,因为这个类看起来非常紧密。我宁愿把它分成3个类:一个真正的支持bean,一个无状态服务和一个模型实体。此外,还应确保未将视图构建时标记或属性绑定到视图范围bean的属性。否则,它确实可以保证在每一个请求上重建。
See also:
- JSTL in JSF2 Facelets... makes sense?
- @PostConstruct method is called even if the ManagedBean has already been instantiated (e.g. on AJAX-calls)
JSF2 Facelets中的JSTL有意义吗?
即使ManagedBean已经被实例化(例如,在AJAX调用上),也会调用@PostConstruct方法
By the way, the eager=true
has only effect in @ApplicationScoped
beans.
顺便说一句,eager = true只对@ApplicationScoped bean有效。
#2
1
The problem is probably the @Model
stereotype (was, as you already removed it). It combines @Named
and @RequestScoped
and makes the bean a CDI request scoped bean. CDI managed beans should be resolved before JSF managed beans and therefore the @ViewScoped
has no effect (it creates a JSF managed bean).
问题可能是@Model构造型(就像你已经删除它一样)。它结合了@Named和@RequestScoped,并使bean成为CDI请求范围的bean。应该在JSF托管bean之前解析CDI托管bean,因此@ViewScoped没有效果(它创建了一个JSF托管bean)。