JSF 2.0:如何添加UIComponents及其内容以查看根目录? [英] JSF 2.0: How to add UIComponents and their contents to view root?

查看:157
本文介绍了JSF 2.0:如何添加UIComponents及其内容以查看根目录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建自定义UIComponent,并在其中添加元素(和其他库存UIComponents).该组件显示正常,但是无法在ViewRoot中找到它.

假设我有:

ResponseWriter writer;

@Override
public void encodeBegin(FacesContext context) throws IOException {
    writer = context.getResponseWriter();
    writer.startElement("div", this);
    writer.writeText("testing", null);
    writer.writeAttribute("id", getClientId(context) + ":testDiv", null);
}

@Override
public void encodeEnd(FacesContext context) throws IOException {
    writer.endElement("div");        
}

添加为:

<x:myUiComponent id="myComponent" />

这样可以,但是我无法从ViewRoot中找到该组件或其子div:

context.getViewRoot().findComponent("myComponent");  // returns null
context.getViewRoot().findComponent("myComponent:testDiv");  // returns null
findComponent("myComponent:testDiv");  // called within the custom component, throws java.lang.IllegalArgumentException?

当我尝试添加其他UIComponent作为自定义组件的子代时,也会遇到相同的问题-它们成功呈现,但是由于我的自定义组件本身不驻留在组件树中,因此无法从组件树中找到.

将组件放入组件树的诀窍是什么?

编辑:调整标题以更好地反映问题.

解决方案

这是由一个愚蠢的错误引起的.正如人们可能会想到的那样,添加的UIComponent 确实会自动添加到ViewRoot.但是,我从另一个自定义UIComponent(我没有提到,因为我忘记了它的存在)中调用了一个自定义UIComponent(我在问题中正在谈论的那个),如下所示:

UICodeEditor:

@Override
public void encodeAll(FacesContext context) throws IOException {
    UIEditPanel editor = new UIEditPanel();
    editor.encodeAll(context);
}

然后在类似以下的模板中将其称为:

<!-- codeEditor is taghandler for UICodeEditor -->
<x:codeEditor />

在这里,UICodeEditor是自动添加到ViewRoot的,但是其中的UIEditPanel却没有,因为我只是在调用encodeAll(context),所以UIEditPanel无法知道其内容的父母.一个快速的解决方法是手动设置子组件的父组件:

editor.setParent(this);

替代方法(可能更好)是从UIComponentBase扩展(如我们通常所做的那样),而不是手动调用encodeAll(context),而只是将组件作为getChildren.add(...)的子代添加到encodeBegin(...)而不是encodeAll(...):

@Override
public void encodeBegin(FacesContext context) throws IOException {
    UIEditPanel editor = new UIEditPanel();
    getChildren().add(editor);
}

getChildren().add()在内部将当前组件添加为子组件的父组件.

考虑子创建的位置,如果不需要使用ResponseWriter(最好是直接在构造函数中构建它们,而不完全覆盖encodeXXX方法,则可能会更好)(如果有,则需要覆盖那些).但是,您可以根据需要更灵活地覆盖和手动调用编码.

还要注意,自定义UIComponent不能直接成为<f:ajax render=目标,因为它没有由DOM树中的DOM元素表示.这种情况与复合组件相同,在这种情况下,我倾向于将复合组件实现包装到JSF管理的panelGroup中,以便稍后可以重新呈现内容.

I am building a custom UIComponent and adding elements (and other stock UIComponents) inside it. The component renders ok, however it cannot be found from the ViewRoot.

Let's say I have:

ResponseWriter writer;

@Override
public void encodeBegin(FacesContext context) throws IOException {
    writer = context.getResponseWriter();
    writer.startElement("div", this);
    writer.writeText("testing", null);
    writer.writeAttribute("id", getClientId(context) + ":testDiv", null);
}

@Override
public void encodeEnd(FacesContext context) throws IOException {
    writer.endElement("div");        
}

Adding that as:

<x:myUiComponent id="myComponent" />

This renders ok, however I cannot find the component or it's child div from the ViewRoot:

context.getViewRoot().findComponent("myComponent");  // returns null
context.getViewRoot().findComponent("myComponent:testDiv");  // returns null
findComponent("myComponent:testDiv");  // called within the custom component, throws java.lang.IllegalArgumentException?

The same problem applies when I try to add other UIComponents as my custom component's children - they render succesfully, however cannot be found from the component tree as my custom component itself doesn't reside there.

What's the trick here to get the components into the component tree?

Edit: Adjusted the title to better reflect the question.

解决方案

This was caused by a stupid mistake. As one would suppose, the added UIComponent does get automatically added to ViewRoot. I was, however, calling a custom UIComponent (the one I was talking about in the question) from inside my other custom UIComponent (which I din't mention because I forgot that it was there) like this:

UICodeEditor:

@Override
public void encodeAll(FacesContext context) throws IOException {
    UIEditPanel editor = new UIEditPanel();
    editor.encodeAll(context);
}

Then called this in a template like:

<!-- codeEditor is taghandler for UICodeEditor -->
<x:codeEditor />

Here, the UICodeEditor does get automatically added to the ViewRoot, however, UIEditPanel inside it does not, because I was simply calling encodeAll(context) and so the UIEditPanel has no way of knowing its' parent. A quick fix would be to manually set the parent of the child component:

editor.setParent(this);

Alternative approach (maybe better) would be to extend from UIComponentBase (as we normally do) and not manually call encodeAll(context) but just add the component as a child with getChildren.add(...) in encodeBegin(...) and not in encodeAll(...):

@Override
public void encodeBegin(FacesContext context) throws IOException {
    UIEditPanel editor = new UIEditPanel();
    getChildren().add(editor);
}

The getChildren().add() internally adds the current component as parent of the children.

Considering the location of the child creation, it might be better to build them straight in the constructor and not override the encodeXXX methods at all, if there's no need to use ResponseWriter (if there is, then you need to override those). However, it is more flexible to override and manually call encoding, whatever you need.

Also note that a custom UIComponent cannot directly be an <f:ajax render= target, because it isn't represented by a DOM element in the DOM tree. This this the same case as with composite components, where I tend to wrap the composite component implementation into a JSF managed panelGroup so that the contents can be re-rendered later on.

这篇关于JSF 2.0:如何添加UIComponents及其内容以查看根目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆