[英]JSF 1.1: How to display component label instead of clientId in validation messages?
I'm writing a custom component to show validation messages in popups, it works well but I have still a problem: I would like to display component labels instead of cliendIds in validation messages. 我正在编写一个自定义组件来显示弹出窗口中的验证消息,它运行良好但我还有一个问题:我想在验证消息中显示组件标签而不是cliendIds。
I already looked at this question and similars: 我已经看过这个问题和类似的了:
Removing the component Id from validation message when using message bundle in JSF 在JSF中使用消息包时从验证消息中删除组件Id
but I'm using jsf 1.1 and I get a compilation error if I try to set a value for attribute label
or requiredMessage
. 但我正在使用jsf 1.1,如果我尝试为属性
label
或requiredMessage
设置一个值,我会收到编译错误。 So I tried assigning a label to the component using an <outputLabel />
: 所以我尝试使用
<outputLabel />
为组件分配标签:
<h:outputLabel for="phone" value="Phone number" />
<h:inputText id="phone" required="true" value="#{backingBean.phoneNumber}" />
with no effect. 没有效果。
Is there a simple way in jsf 1.1 to make label appear in validation messages instead of client id? 在jsf 1.1中是否有一种简单的方法可以使标签出现在验证消息中而不是客户端ID? If not, how could I, given a component, retrieve its related label component to do the work in Java code?
如果没有,在给定组件的情况下,我如何检索其相关的标签组件以在Java代码中完成工作?
Thanks. 谢谢。
I found a solution which does not require to modify existing JSF code. 我找到了一个不需要修改现有JSF代码的解决方案。
HtmlMessagesRenderer
, which is capable of use a component label instead of its id HtmlMessagesRenderer
,它能够使用组件标签而不是其id HtmlMessagesRenderer#findInputId
to retrieve the Id of the component with messages HtmlMessagesRenderer#findInputId
检索带有消息的组件的Id HtmlMessagesRenderer#findInputLabel
to retrieve the Label of the component with messages HtmlMessagesRenderer#findInputLabel
检索带有消息的组件的Label Below is an excerpt from the code of my component Render encodeBegin
method, in which I made two separated loops, the first for component messages the other for global messages. 下面是我的组件Render
encodeBegin
方法的代码的摘录,其中我做了两个独立的循环,第一个用于组件消息,另一个用于全局消息。
Note that FacesContext#getClientIdsWithMessages
returns also null
, which is considered the clientId for global messages. 请注意,
FacesContext#getClientIdsWithMessages
也返回null
,它被视为全局消息的clientId。
Note that, because the component itself manages to retrieve and use the component label, if exists; 请注意,因为组件本身设法检索并使用组件标签,如果存在; this solution it only need to place a
<myCustomMessages />
tag in JSF page code. 这个解决方案只需要在JSF页面代码中放置一个
<myCustomMessages />
标记。
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
// ....
// replace id with label in messages for components
Iterator<String> clientIdsWithMessages=context.getClientIdsWithMessages();
while(clientIdsWithMessages.hasNext()){
String clientIdWithMessages=clientIdsWithMessages.next();
if(clientIdWithMessages!=null){
Iterator<FacesMessage> componentMessages=context.getMessages(clientIdWithMessages);
while(componentMessages.hasNext()){
String stringMessage=componentMessages.next().getDetail();
try{
String inputId =findInputId(context, clientIdWithMessages);
String inputLabel = findInputLabel(context, clientIdWithMessages);
if(inputId!=null && inputLabel!=null)
stringMessage=stringMessage.replace(inputId, inputLabel);
} catch(Exception e){
// do nothing in this catch, just let the message be rendered with the componentId instead of a label }
msgBuilder.append(stringMessage);
msgBuilder.append("<br />");
}
}
}
// process global messages
Iterator<FacesMessage> globalMessages=context.getMessages(null);
while(globalMessages.hasNext()){
FacesMessage message=globalMessages.next();
msgBuilder.append(message.getDetail());
msgBuilder.append("<br />");
}
// ...
Here is a reference to HtmlMessagesRenderer#findInputLabel
source code, to take a look on how it works. 这里是对
HtmlMessagesRenderer#findInputLabel
源代码的引用,以了解它是如何工作的。
I think of one solution. 我想到了一个解决方案。 You can add new
PhaseListener
which will look for PhaseEvent
with PhaseId = RENDER_RESPONSE
and inside it's beforePhase method write something like this: 您可以添加新的
PhaseListener
,它将查找具有PhaseId = RENDER_RESPONSE
PhaseEvent
,并在其之前的beforePhase方法中写入如下内容:
public class MyPhaseListener implements PhaseListener {
private void findKeyValuePairInTree(UIComponent root,
Map<String, String> map) {
if (root instanceof HtmlOutputLabel) {
map.put(((HtmlOutputLabel) root).getFor(),
((HtmlOutputLabel) root).getValue());
}
if (root.getChilder() != null && !root.getChildren().isEmpty()) {
for (UIComponent child : root.getChilder()) {
findKeyValuePairInTree(child, map);
}
}
private HashMap<String, String> idToLabelMap= new HashMap<String,String>();
public void beforePhase(PhaseEvent event) {
if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE) {
findKeyValuePairInTree(FacesContext.getCurrentInstance().getViewRoot(),
idToLabelMap);
// after above function finished execution in idToLabelMap will be all
// pairs of component ID used in standard FacesMessage as key
// and HtmlOutputLabel value attr used as value
Set<String> keySet = idToLabelMap.keySet();
for(String key : keySet) {
Iterator messages = FacesContext.getCurrentInstance().getMessages(key);
while (iterator.hasNext) {
FacesMessage msg = (FacesMessage) iterator.next();
// now replace all occurences of clientId with label value from map
msg.setSummary(msg.getSummary().replaceAll(key, idToLabelMap.get(key)));
msg.setDetails(msg.getDetails().replaceAll(key, idToLabelMap.get(key)));
}
}
FacesContext.getCurrentInstance().getMessages();
}
}
...
}
Now in Render Phase which comes after this method all messages in FacesContext.getCurrentInstance().getMessages()
will have changed clientId
with label value and because Validation Phase is before Render Phase all validation will be passed or failed - no more messages will come from validation. 现在在此方法之后的Render阶段,
FacesContext.getCurrentInstance().getMessages()
所有消息都将更改带有标签值的clientId
,并且因为验证阶段在渲染阶段之前所有验证都将通过或失败 - 不再有消息来自验证。
The only problem is when you use in for
attribute of HtmlOutputLabel
instance the same id twice or more because in different forms can be same ids used for components. 唯一的问题是,当你在使用
for
属性HtmlOutputLabel
因为在不同形式的实例相同的ID两次以上可用于组件的编号相同。 Then You can in for
attr inside <h:outputLabel>
use more sophisticated id, for example clue it with form id or something like this. 然后你可以在
for
<h:outputLabel>
里面<h:outputLabel>
使用更复杂的id,例如用表格id或类似的东西来表达它。
I hope this will help. 我希望这将有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.