Для рамки форм, в которой я предпочитаю использовать JSF в качестве реального интерфейса интерфейса, я ищу способ информирования родительского компонента, если в дочернем компоненте значение изменяется. Facelet базового «контроля» выглядит следующим образом (тела/головы опущены, так как никто не может запустить его в любом случае без десятка классов):Подписывание PostValidationEvent из динамического дочернего компонента
<xf:input ref="/my/xpath/value">
<xf:label>Label</xf:label>
</xf:input>
компонент xf:input
, который я разработал, динамически создает реальную составляющую щ (PrimeFaces) в зависимости от типа значения, которое указывает ref="/my/xpath/value"
. Этот реальный компонент ui создается в событии preRenderView, как это сделано в этом примере. Это обрабатывается следующим способом в родительском управлении
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
if (!context.isPostback()) {
control = createControl(context);
//context.getApplication().unsubscribeFromEvent(PostValidateEvent.class, getControl().getClass(), this);
control.subscribeToEvent(PostValidateEvent.class, this);
}
}
Фактические элементы управления все имеет программно добавлен обработчик Ajax добавил к нему, что позволяет просто обрабатывать конкретный вход («неявного АЯКС») , Стандартные проверки компонентов JSF обычно применяются, и все это отлично работает.
Проблема/вызов заключается в том, что в этом компоненте «обертка» я хочу получать информацию об изменениях значений после проверки. Моя первая мысль была нам subscribeEvent на динамически добавляемые элементы управления, как это:
control.subscribeToEvent(PostValidateEvent.class, this);
Подписавшие работает, но на постбэка, NPE брошен в UIComponent
(Mojarra 2.2.9), так как wrapped
равна нулю в следующем методе
public boolean isListenerForSource(Object component) {
if (wrapped instanceof SystemEventListener) {
return ((SystemEventListener) wrapped).isListenerForSource(component);
} else {
return instanceClass.isAssignableFrom(component.getClass());
}
}
Это может быть потому, что фактический компонент, кажется, вновь создается, когда данные передаются ан, следовательно, «подписки» теряется.
Регистрация на ViewRoot
не работает, так как источником события является всегда ViewRoot
, и регистрация на Application
проста.
Возможно, я ищу решение в неправильном направлении, но пока я не знаю. Имейте в виду, что я не имею прямого контроля над созданными элементами управления ui, и я не хочу переопределять их средства визуализации, если я могу предотвратить. Таким образом, передача родительского элемента из дочернего элемента управления не является обязательной.
Другие вещи, которые я пробовал:
- Использование valueChangeListeners, но это не работает, либо с большим количеством других проблем (в том числе способов сделать это расширяемый)
- Использование композитных компонентов с привязкой, но это не удалось, включая их динамически , требующие именования контейнеров, которые конфликтуют с идентификатором, необходимым для остальной части фреймворка, положениями меток, подсказок и предупреждений в xhtml и/или в результате dom
- Обработчики тегов для управления деревом при их создании
Это все с Mojarra до 2.2.9 (не проверял новые или еще MyFaces)
Компоненты лучше всего создавать во время просмотра времени просмотра. 'PreRenderView' должен быть' postAddToView'. Ты это пробовал? – BalusC
Да, я могу понять это, но все серьезные примеры, которые я нашел (включая сообщения из консалтинга Кеннарда о MetaWidget), делают это так. Хотя сейчас я его ищу, я вижу [тот, который использует postAddToView] (http://www.beyondjava.net/blog/change-jsf-2-2-component-tree-tagdecorators-taghandlers/). Позвольте мне попробовать ... – Kukeltje
@BalusC: Я попытался сменить его на событие «PostAddToView», а затем в «UIComponent» нет «NPC» в «PostValidateEvent», но больше нет события: - (... Существует еще большая разница: динамически добавленный ребенок полностью потерян, по крайней мере, при сбрасывании детей в 'PostRestoreStateEvent'. Его просто нет. Я тогда подумал о добавлении' postValidateEvent' к элементу управления в PostRestoreStateEvent это тот момент, когда мне это действительно нужно. Замечательно это работает, но только один раз. Во втором запросе к тому же компоненту NPE снова появляется. – Kukeltje