在JSF Ajax响应XML中插入自定义标记

时间:2012-08-30 11:43:00

标签: ajax jsf

Consoder以下代码:

<h:commandButton value="do" action="#{testBacking.do}">
   <f:ajax execute="@all" render="@all" listener="#{testBacking.listener}"/>
</h:commandButton>

我希望在Ajax响应XML中有一个自定义标记(基于服务器逻辑的值),如下所示:

<isValidationFailed> true </isValidationFailed>

我可以使用此数据重新启用按钮(在Ajax开始时禁用该按钮,以避免双击),如果验证失败。

如何实现这一目标(最好不使用任何JSF第三方库)?

修改

更准确地说,示例代码应该是这样的:

<h:commandButton id="myButton" value="do" action="#{testBacking.do}">
 <f:ajax execute="id1" render="id2 myButton" listener="#{testBacking.listener}"/>
</h:commandButton>

1 个答案:

答案 0 :(得分:7)

这只能通过使用PartialViewContext加载到JSF应用程序中的自定义PartialViewContextFactory来实现。自定义PartialViewContext应该会在PartialResponseWriter上返回自定义PartialViewContext#getResponseWriter()。在此自定义PartialResponseWriter中,您应该可以通过调用startExtension()中的endExtension()endDocument()来添加XML响应的扩展。类似的东西:

@Override
public void endDocument() throws IOException {
    Map<String, String> attributes = new HashMap<String, String>();
    attributes.put("name1", "value1");
    attributes.put("name2", "value2");
    startExtension(attributes);
    write("lorem ipsum");
    endExtension();
    super.endDocument();
}

这将以XML响应结束

<extension name1="value1" name2="value2">lorem ipsum</extension>

data.responseXML函数中的jsf.ajax.addOnEvent()可以使用此文件。


这是一个完整的启动示例,您可以在特定情况下使用它:

MyPartialViewContextFactory提供自定义部分视图上下文:

public class MyPartialViewContextFactory extends PartialViewContextFactory {

    private PartialViewContextFactory wrapped;

    public MyPartialViewContextFactory(PartialViewContextFactory wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public PartialViewContext getPartialViewContext(FacesContext context) {
        return new MyPartialViewContext(wrapped.getPartialViewContext(context));
    }

}

MyPartialViewContext提供自定义部分响应编写器:

public class MyPartialViewContext extends PartialViewContextWrapper {

    private PartialViewContext wrapped;
    private PartialResponseWriter writer;

    public MyPartialViewContext(PartialViewContext wrapped) {
        this.wrapped = wrapped;
        this.writer = new MyPartialResponseWriter(wrapped.getPartialResponseWriter());
    }

    @Override
    public PartialResponseWriter getPartialResponseWriter() {
        return writer;
    }

    @Override
    public void setPartialRequest(boolean isPartialRequest) {
        wrapped.setPartialRequest(isPartialRequest);
    }

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

}

MyPartialResponseWriter<extension id="myextension">与正文一起写为JSON):

public class MyPartialResponseWriter extends PartialResponseWriter {

    public MyPartialResponseWriter(ResponseWriter wrapped) {
        super(wrapped);
    }

    @Override
    public void endDocument() throws IOException {
        startExtension(Collections.singletonMap("id", "myextension"));
        write("{\"validationFailed\": " + FacesContext.getCurrentInstance().isValidationFailed() + "}"); // Consider a JSON serializer, like Google Gson.
        endExtension();
        super.endDocument();
    }

}

要使其运行,请在faces-config.xml

中按如下方式注册工厂
<factory>
    <partial-view-context-factory>com.example.MyPartialViewContextFactory</partial-view-context-factory>
</factory>

以下是您在<extension id="myextension">中访问,解析和使用jsf.ajax.addOnEvent()的方法:

jsf.ajax.addOnEvent(function(data) {
    if (data.status == "success") {
        var args = JSON.parse(data.responseXML.getElementById("myextension").firstChild.nodeValue);

        if (args.validationFailed) {
            // ...
        }
        else {
            // ...
        }
    }
});

但是您的特定功能要求可以通过不同的,可能更简单的方式实现。只需让ajax请求更新按钮本身,当有成功的回发方式时,让按钮的disabled属性评估true

<h:commandButton id="myButton" value="do" action="#{testBacking.do}" 
    disabled="#{facesContext.postback and not facesContext.validationFailed}">
    <f:ajax execute="id1" render="@this id2" listener="#{testBacking.listener}"/>
</h:commandButton>