2013-11-18 4 views
0

Здравствуйте снова JSF Gurus.Пользовательский рендер не запускает прослушиватель для события ajax

Я ищу помощь в пользовательских рендерах и обработчиках ajax. Наш проект не может использовать обычные переключатели и флажков рендеринга по мере их рендеринга в таблицах, и это противоречит нашим корпоративным стандартам. Мы также не можем использовать библиотеки сторонних компонентов.

У нас есть собственный рендерер, который мы использовали в нескольких проектах, которые работают отлично. Однако в этом конкретном проекте мне нужно сделать обработчик ajax для некоторых переключателей. Следуя советам в ответе на вопрос this question, я добавил вызов RenderKitUtils.renderSelectOnclick();, и пока он кажется, что он отображает один и тот же javaScript в качестве стандартного средства визуализации, и действительно, панель сети firebug показывает исходящий запрос, мой слушатель изменения значения не запускается, и я ищу помощь, почему (он стреляет отлично со стандартным визуализатором)

часть кода: Во-первых, создание обработчика АЯКС (кнопка радио создается программно)

  AjaxBehavior valueChangeAction = (AjaxBehavior) FacesUtils.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID); 

     valueChangeAction.addAjaxBehaviorListener(new ProbeQuestionListener(currentQuestion, "probeDiv" + questionNumber, 
      probeDiv)); 

     selectUI.addClientBehavior("valueChange", valueChangeAction); 
     valueChangeAction.setRender(Collections.singletonList("probeDiv" + questionNumber)); 

Wih стандартный визуализатор, это производит:

<table id="answer_1" class="marginLeft1a"> 
    <tbody> 
    <tr> 
     <td> 
     <input id="answer_1:0" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="0" name="answer_1"> 
     <label for="answer_1:0"> Yes</label> 
     </td><td> 
     <input id="answer_1:1" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="1" name="answer_1"> 
     <label for="answer_1:1"> No</label> 
    </td> 
    </tr> 

и все хорошо. Запрос ajax отправляется, и мой слушатель на стороне сервера запускается.

Соответствующие части моего пользовательского визуализатора:

public void encodeEnd(final FacesContext p_context, final UIComponent p_component) throws IOException { 

    /* set up convenience fields */ 
    context = p_context; 
    component = p_component; 
    componentId = component.getClientId(context); 

    // rendering divs etc omitted. 

    while (iterator.hasNext()) { 
     final UIComponent childComponent = iterator.next(); 
     // irrelevant code omited 
     if ("javax.faces.SelectItem".equals(childComponent.getFamily())) { 
      renderSelectItem(idIndex, childComponent); 
      idIndex++; 
     } 
    } 
} 

private void renderSelectItem(final int p_idIndex, final UIComponent p_childComponent) throws IOException { 
     // unrelated code omitted 
     writer.startElement("input", component); 
     writer.writeAttribute("type", getInputType(), null); 
     writer.writeAttribute("id", p_childComponentId, "id"); 
     writer.writeAttribute("name", componentId, "clientId"); 
     RenderKitUtils.renderSelectOnclick(context, component, false); 
     writer.endElement("input"); 
     // unrelated code omitted 
} 

Update: Метод декодирования в базовом классе для моего рендерер:

@Override 
public void decode(final FacesContext p_context, final UIComponent p_component) { 

    final Map<String, String> valuesMap = p_context.getExternalContext().getRequestParameterMap(); 

    final UIInput input = (UIInput) p_component; // NOSONAR 

    final Object value = valuesMap.get(input.getClientId(p_context)); 
    // System.out.println("radio button decode: found " + value); 
    input.setSubmittedValue(value); 
} 

Это делает как:

<span class="marginLeft1a" id="answer_1"> 
    <label for="answer_1:0"> 
    <input type="radio" value="0" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:0"> 
    Yes 
    </label> 
    <label for="answer_1:1"> 
     <input type="radio" value="1" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:1"> 
     No 
    </label> 
</span> 

Как вы можете видеть, обработчик кликов javaScript идентичен, как и значения атрибута имени и идентификатора входные теги. Хотя это вызывает запрос Ajax, слушатель не запускается на стороне сервера, как и в первой версии.

Любые идеи?

+0

'decode()' метод отвечает за поиск и ожидание событий ajax. Однако я не вижу этого в фрагменте кода. Правильно ли я предполагаю, что на самом деле у вас их нет, и поэтому вы столкнулись с этой проблемой?В любом случае, какой суперкласс является вашим настраиваемым средством визуализации? – BalusC

+0

Ooops, мой плохой. Я обновил вопрос, чтобы показать метод декодирования. Наверное, мне нужен код события, а? Помоги пожалуйста! –

ответ

3

decode() метод Renderer (или UIComponent, если нет никакого средства визуализации) должен декодировать запрос Ajax на основе javax.faces.behavior.event параметра запроса и вызвать ClientBehavior#decode() на соответствие клиента поведения.

В принципе, логика выглядит следующим образом:

Map<String, List<ClientBehavior>> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); 

if (!behaviors.isEmpty()) { 
    Map<String, String> params = context.getExternalContext().getRequestParameterMap(); 
    String behaviorEvent = params.get("javax.faces.behavior.event"); 

    if (behaviorEvent != null) { 
     List<ClientBehavior> behaviorsForEvent = behaviors.get(behaviorEvent); 

     if (behaviorsForEvent != null && !behaviorsForEvent.isEmpty()) { 
      String behaviorSource = params.get("javax.faces.source"); 

      if (isBehaviorSource(context, behaviorSource, component.getClientId())) { 
       for (ClientBehavior behavior: behaviorsForEvent) { 
        behavior.decode(context, component); 
       } 
      } 
     } 
    } 
} 

Учитывая тот факт, что вы используете RenderKitUtils и генерируемый вывод HTML содержит mojarra.ab(), я буду считать, что вы используете Mojarra. В этом случае, возможно, разумнее расширить свой собственный рендер от RadioRenderer, который имеет всю эту логику, уже реализованную в HtmlBasicRenderer и SelectManyCheckboxListRenderer, так что вам не нужно изобретать колесо.

+0

Выглядя многообещающим, однако 'isBehaviorSource (context, behaviorSource, component.getClientId()' возвращает false, поскольку behaviourSource - это answer_1: 0, а clientId - answer_1. Я пытаюсь выполнить обычный отладчик, чтобы увидеть, как это работает, –

+0

Правильно, лучше использовать вместо 'SelectManyCheckboxListRenderer' (или' RadioRenderer'), он имеет правильную логику 'isBehaviorSource()'. – BalusC

+0

Легенда! Еще раз, вы оказались бесценными! Я думаю, что пришло время поблагодарить вас за всю фантастическую помощь, которую вы оказали мне в моем путешествии JSF прямо и косвенно. Проверьте свой адрес электронной почты;) –

Смежные вопросы