首页 > 解决方案 > 有没有办法从 UIComponent 对象获取生成的 HTML 作为 String 并在 RENDER 响应阶段正确绑定所有 ajax 侦听器?

问题描述

这是对这个问题的跟进。

环境

Primefaces 8.0.RC3
JSF 2.2.15
Tomcat 8.5.47

背景

我有一个扩展的自定义 JSF 组件UIComponentBase

public final class Map extends UIComponentBase implements Widget {
    // resolveWidgetVar
    // a constructor
    // getters/setters
}

MapRenderer哪个将渲染该组件。

public final class MapRenderer extends CoreRenderer {

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        final Map map = (Map) component;

        encodeMarkup(context, map);
        encodeScript(context, map);
    }

    private void encodeMarkup(FacesContext context, Map map) throws IOException {
        // renders a div
    }

    private void encodeScript(FacesContext context, Map map) throws IOException {
        // renders a script with PF.cw(widgetName, widgetVar, cfg)
    }

}

它将是一个基于传单的地图,其中一个图例被定义为一个SelectManyMenu组件。图例既是图例又是过滤器。挑战在于很好地将所需的一切传递给 JS 端。为此,我采用了这个答案所示的方法- 我基本上编码了一个以编程方式创建SelectManyMenu到我的Writer.

然后,我将它分成两部分(因为应该定义控件(这里是图例)的方式 - 请参见下面的函数):

  1. 一个 JS 片段executeInteractiveLegendScript(用一行来创建一个 Primefaces 小部件)和

  2. HTML 片段getInteractiveLegendHTML(菜单的标记)。


function (configuration) {
    var interactiveLegend = L.control({position: 'bottomleft'});

    interactiveLegend.onAdd = function () {
        var container = L.DomUtil.create('div', 'interactive-legend');
        container.innerHTML = configuration['getInteractiveLegendHTML']();
        return container;
    };

    interactiveLegend.addTo(map);
    configuration['executeInteractiveLegendScript']();
}

configuration是我在 Java 端编译的对象。在某些时候,通过 JS,我将图例添加到地图中。JS 片段正在正确执行,Primefaces 元素正在正确显示 - 这里没有问题。

问题

问题在于为这个以编程方式创建的组件定义客户端行为。

// while rendering the map

SelectManyMenu selectManyMenu = (SelectManyMenu) context.getApplication()
    .createComponent(SelectManyMenu.COMPONENT_TYPE);

// setting children and properies
selectManyMenu.addClientBehavior("change", createAjax(context));

selectManyMenu.encodeAll(context);

创建a的方法ClientBehavior定义如下

private ClientBehavior createAjax(FacesContext context) {
    Application application = context.getApplication();
    ExpressionFactory expressionFactory = application.getExpressionFactory();
    AjaxBehavior behavior = (AjaxBehavior) application.createBehavior(AjaxBehavior.BEHAVIOR_ID);

    MethodExpression methodExpression = expressionFactory.createMethodExpression(context.getELContext(), "#{myexpression}", Void.TYPE, new Class[]{String.class});
    AjaxBehaviorListenerImpl listener = new AjaxBehaviorListenerImpl(methodExpression, methodExpression, methodExpression);

    behavior.setProcess("@this");

    // PROBLEM HERE - this listener never gets invoked
    behavior.addAjaxBehaviorListener(listener);

    return behavior;
}

我怀疑我注册此客户行为的地方,是否为时已晚并且听众根本没有正确注册?

问题是如何让它工作,我应该在哪里创建一个菜单实例并绑定所有的属性/监听器。

@BalusC在他的回答中提到

(假设您正处于调用应用程序阶段;当处于渲染响应阶段时,需要以不同的方式完成):

这证实了我做错了什么。

标签: javascriptajaxjsfprimefaces

解决方案


推荐阅读