我可以将一个panelGroup链接到一个没有f:ajax监听器的监听器吗?

时间:2016-04-12 13:25:42

标签: jsf jsf-2

我已将f:ajax标记替换为未放入内联脚本的自制解决方案。它对actionButton感到奇怪。但是我无法让panelGroup的听众工作。原因是无法指定ajax请求产生的bean目标方法应该是什么。换句话说,使用commandButton我可以在action中指定目标bean方法,但panelGroup没有这样的属性;因为我不想使用f:ajax listener,我想替换它。

 <h:commandButton data-widget="jsfajax" value="ajax" action="#{someAction}"/>
$(document).ready(function(){   
    (function(widgets){
        document.body.addEventListener("click", function(e) {
               var w = e.target.getAttribute("data-widget");
               if(w){
                   e.preventDefault();
                   widgets[w](e.target);
               }
            });
    })(new Widgets);
});
function Widgets(){
    this.jsfajax =  function jsfajax(elem){ 
            if(elem.id == ""){
            elem.id = elem.name;
        }
       mojarra.ab(elem,"click",'action','@form',0);  
     }
}

这很有效。

但这显然不会(确实没有,但它不会调用任何东西):

 <h:panelGroup>
    <f:passThroughAttribute name="data-widget" value="jsfajax"/>
    Click here
 </h:panelGroup>

但这样做:

 <h:panelGroup>
    <f:ajax event="click" listener="#{someAction}"/>
    Click here
 </h:panelGroup>

这两个panelGroup都会产生相同的HTML输出,因此我假设它是“记住”该panelGroup上的点击链接到#{someAction}的jsf容器。

我想要做的是在不使用f:ajax listener的情况下重新创建该链接。目前我要使用一个不太优雅的隐藏commandButton。 也许是一个复合组件panelGroup,可以保存“动作链接”,我不知道。

1 个答案:

答案 0 :(得分:0)

您希望实现的目标只能在UICommand组件上实现,而不能在ClientBehaviorHolder组件上实现。一种解决方案是创建一个扩展HtmlCommandLink的自定义组件,该组件呈现<div>而不是<a>,并像<your:div action="#{bean.action}">一样使用它。

最理想的解决方案是更换标准渲染器。例如。 <h:panelGorup>

<render-kit>
    <renderer>
        <component-family>javax.faces.Panel</component-family>
        <renderer-type>javax.faces.Group</renderer-type>
        <renderer-class>com.example.YourPanelGroupRenderer</renderer-class>
    </renderer>
</render-kit>

基本上,这些渲染器应跳过渲染<f:ajax> - 相关on*属性,而是渲染您的data-widget属性(最好还有其他属性代表现有<f:ajax>属性,例如{ {1}},executerender等)。您还应该针对标准API进行编程,而不是Mojarra特定的API。即直接使用delay代替jsf.ajax.request()快捷方式。

通过这种方式,您可以保持视图符合JSF标准。您和未来的开发人员在编写JSF代码时甚至不需要学习/思考“专有”API。您只需继续使用mojarra.ab()即可。您只需通过webapp中的JAR插入自定义渲染和脚本,就可以了。 JAR甚至可以在所有其他现有的JSF应用程序上重用。它甚至可能变得流行,因为内联脚本确实被认为是不好的做法。

这只是一些代码,对于首发来说并不一定是微不足道的。

另一种方法是将标准响应编写器替换为自定义响应编写器,其中覆盖writeAttribute()并检查属性名称是否以<h:panelGroup><f:ajax>开头,然后按照您的想法处理它们。例如。解析它并编写不同的属性。这是一个启动示例,它也识别on

<h:panelGroup><f:ajax>

public class NoInlineScriptRenderKitFactory extends RenderKitFactory {

    private RenderKitFactory wrapped;

    public NoInlineScriptRenderKitFactory(RenderKitFactory wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void addRenderKit(String renderKitId, RenderKit renderKit) {
        wrapped.addRenderKit(renderKitId, renderKit);
    }

    @Override
    public RenderKit getRenderKit(FacesContext context, String renderKitId) {
        RenderKit renderKit = wrapped.getRenderKit(context, renderKitId);
        return (HTML_BASIC_RENDER_KIT.equals(renderKitId)) ? new NoInlineScriptRenderKit(renderKit) : renderKit;
    }

    @Override
    public Iterator<String> getRenderKitIds() {
        return wrapped.getRenderKitIds();
    }

}

public class NoInlineScriptRenderKit extends RenderKitWrapper {

    private RenderKit wrapped;

    public NoInlineScriptRenderKit(RenderKit wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ResponseWriter createResponseWriter(Writer writer, String contentTypeList, String characterEncoding) {
        return new NoInlineScriptResponseWriter(super.createResponseWriter(writer, contentTypeList, characterEncoding));
    }

    @Override
    public RenderKit getWrapped() {
        return wrapped;
    }

}

您拥有自由的最重要部分是最后一个片段中的public class NoInlineScriptResponseWriter extends ResponseWriterWrapper { private ResponseWriter wrapped; public NoInlineScriptResponseWriter(ResponseWriter wrapped) { this.wrapped = wrapped; } @Override public ResponseWriter cloneWithWriter(Writer writer) { return new NoInlineScriptResponseWriter(super.cloneWithWriter(writer)); } @Override public void writeAttribute(String name, Object value, String property) throws IOException { if (name.startsWith("on")) { if (value != null && value.toString().startsWith("mojarra.ab(")) { super.writeAttribute("data-widget", "jsfajax", property); } } else { super.writeAttribute(name, value, property); } } @Override public ResponseWriter getWrapped() { return wrapped; } } 方法。上面的启动示例只是盲目地检查writeAttribute()属性值是否以Mojarra特定on*开头,然后写入"mojarra.ab("。换句话说,每一个(自然使用!)data-widget="jsfajax"都将以这种方式重写。您可以继续使用<f:ajax><h:commandLink><f:ajax>自然方式。

时,不要忘记处理其他<h:panelGroup><f:ajax>属性。

要使其运行,请在<f:ajax>

中注册如下
faces-config.xml

您仍然需要考虑现有的特定于实现的细节(幸运的是,只有两个:Mojarra和MyFaces)。

另见: