如何从复合组件外部设置复合组件的值

How to set the value of a composite component from outside the composite component

所以,我有一个复合组件。在其中,我有一个常规文本输入,使用复合组件的属性之一作为值。

<h:inputTextarea id="#{cc.attrs.id}Text" value="#{cc.attrs.value}">
    <f:ajax event="blur" listener="#{someBean.onBlur}" />
</h:inputTextarea>

如您所见,我在文本框中有一个事件。此事件打开一个弹出窗口并使用复合控件上的文本填充它。它还保存对调用它的复合控件的引用。让我告诉你:

public void onBlur(AjaxBehaviorEvent event) {
    this.fieldReference = (UIInput) event.getSource();

    this.formula = this.fieldReference.getValueExpression("value")
            .getValue(FacesContext.getCurrentInstance().getELContext())
            .toString();

    this.displayPopup = true;
}

到目前为止,还不错。现在,当我尝试关闭弹出窗口然后使用在弹出窗口中输入的值更新复合组件上的值时,问题就来了。我尝试这样做:

public void accept(ActionEvent event) {
    this.fieldReference
            .getValueExpression("value")
            .setValue(FacesContext.getCurrentInstance().getELContext(), this.formula);
    this.displayPopup = false;
}

当我尝试这样做时,我得到:

javax.el.PropertyNotFoundException: //C:/myProject/Path/compositeComponentPage.xhtml at line 22 and column 183 value="#{cc.attrs.value}": Target Unreachable, identifier 'cc' resolved to null

在我看来,该请求的 EL 上下文是不同的,因此无法解析复合组件表达式中的变量...但是如果我还尝试存储复合组件请求中对 ELContext 对象的引用(在 onBlur() 方法上),然后当我尝试在 accept() 中使用它时,我得到:

javax.faces.event.AbortProcessingException: java.lang.IllegalStateException: Error the FacesContext is already released!

使用 MyFaces 2.0.2(WebSphere 8.5 自带的版本,我相信他们修改过),和 RichFaces 4.2.3。

有什么想法吗?

嗯,我好像找到了解决办法。环顾四周,我发现这个小知识在一个完全不相关的article on BalusC's blog:

The backing component instance has basically a lifetime of exactly one HTTP request. This means that it's recreated on every single HTTP request, like as a request scoped managed bean.

因此,保存对组件的引用是一件非常糟糕的事情。相反,我保存了组件的客户端 ID 并在关闭弹出窗口时查找它,然后使用 setValue,这在以前是行不通的。像这样:

public void onBlur(AjaxBehaviorEvent event) {
    UIInput component = (UIInput) event.getSource();
    this.componentId = component.getClientId(FacesContext.getCurrentInstance());

    this.formula = component.getValueExpression("value")
        .getValue(FacesContext.getCurrentInstance().getELContext())
        .toString();

    this.displayPopup = true;
}

public void accept(ActionEvent event) {
    UIInput component = (UIInput) FacesUtil.findComponent(this.componentId);
    component.setValue(this.formula);

    this.displayPopup = false;
}

所以...我想谢谢,BalusC,你再次拯救了这一天!! :)