【问题标题】:Inserting custom tag in JSF Ajax response XML在 JSF Ajax 响应 XML 中插入自定义标记
【发布时间】:2012-08-30 11:42:59
【问题描述】:

考虑以下代码:

<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 3rd 方库)?

编辑:

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

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

【问题讨论】:

  • 具体问题是正确的(答案并非微不足道——归结为“您需要像 PrimeFaces/RichFaces 那样实现自定义 PartialViewContext。”),但示例使用情况令人困惑。你有一个render="@all",它会总是重新启用按钮,不管结果如何......你也可以改用disabled="#{facesContext.postback and not facesContext.validationFailed}"
  • 我已更正并更新了我的帖子。 :-)
  • 我想我可以重新渲染按钮(只是为了重新启用它)并使用您建议的 EL。与其他样板代码相比,这似乎是一个聪明的解决方案。非常感谢。
  • 好的 :) 但是,据我所知,这个具体的问题在 SO 之前没有被问过,所以我还是会回答的。
  • 我从来没有想过在 EL 中使用 facesContext,但是你的建议真的很有帮助。再次感谢。

标签: ajax jsf


【解决方案1】:

这只能通过自定义PartialViewContext 实现,您可以使用PartialViewContextFactory 将其加载到您的JSF 应用程序中。自定义PartialViewContext 应该反过来在PartialViewContext#getResponseWriter() 上返回自定义PartialResponseWriter。在这个自定义的PartialResponseWriter 中,您应该能够通过在endDocument() 中调用startExtension()endExtension() 来为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.responseXMLjsf.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 写入&lt;extension id="myextension"&gt;,正文为 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>

以下是您在jsf.ajax.addOnEvent() 中访问、解析和使用&lt;extension id="myextension"&gt; 的方法:

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>

【讨论】:

  • 这简直太完美了!再次感谢!
  • +1 但不是直接在字符串中写入 JSON 格式,我建议使用 JSONObject 来封装它: startExtension([...]); JSONObject extensionContent = new JSONObject(); extensionContent.put("param", valueObject);写(extensionContent.toString());
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
相关资源
最近更新 更多