Значение события Ajax Listener, похоже, вызывает onClick вместо onChange - PullRequest
3 голосов
/ 29 ноября 2011

У меня есть вложенный список вопросов, которые я хотел бы отобразить. Сначала я отображаю вопросы уровня 1, а затем отображаются подзапросы на основе ответов пользователей на родительский вопрос. Все вопросы имеют переключатель, а некоторые вопросы имеют поле ввода для дополнительной информации, которая отображается, когда пользователь выбирает «Да»

Вот мой код JSF с вложенными таблицами данных. Обратите внимание, что я вытащил форматирование этих вопросов, чтобы просто задать вопрос на форуме, поэтому они могут выглядеть «неуместно», если вы скопируете этот код в свою среду и запустите код:

<h:dataTable id="questionTable" var="q" value="#{generalQuestionBean2.questions.questions}">
<h:column><h:panelGroup id="questionGrp">
#{q.question} <h:selectOneRadio value="#{q.answer}">
<f:selectItem itemValue="1" itemLabel="Yes"/>
<f:selectItem itemValue="0" itemLabel="No"/>
<f:ajax event="valueChange" execute="@form"
    render="questionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio> <h:inputText value="#{q.addnInfo}"
rendered="#{q.answer eq '1' and q.field ne 'otherCov'}"></h:inputText>

<h:panelGroup id="questionGrpSubs" rendered="#{q.addnQuestions ne null and q.answer eq '1'}">
<h:dataTable id="subQuestionTable" var="subq" value="#{q.addnQuestions}">
<h:column><h:panelGroup id="subQuestionGrp">
->#{subq.question} <h:selectOneRadio id="answer" value="#{subq.answer}"> 
 <f:selectItem itemValue="1" itemLabel="Yes"/>
 <f:selectItem itemValue="0" itemLabel="No"/>
 <f:ajax event="valueChange" execute="@form"
    render="subQuestionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{subq.addnInfo}"
rendered="#{subq.answer eq '1' and subq.field ne 'voluntaryComp' and subq.field ne 'uslh'}"></h:inputText>

<h:panelGroup id="questionGrpSubs2" rendered="#{subq.addnQuestions ne null and subq.answer eq '1'}">
<h:dataTable id="sub2QuestionTable" var="sub2q" value="#{subq.addnQuestions}">
<h:column><h:panelGroup id="sub2QuestionGrp">
-->#{sub2q.question} <h:selectOneRadio id="answer" value="#{sub2q.answer}"> 
 <f:selectItem itemValue="1" itemLabel="Yes"/>
 <f:selectItem itemValue="0" itemLabel="No"/>
 <f:ajax event="valueChange" execute="@form"
    render="sub2QuestionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{sub2q.addnInfo}"
rendered="#{sub2q.answer eq '1'}"></h:inputText>

</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable>

Вот код для функции сброса на компоненте поддержки:

private void reset(AjaxBehaviorEvent event) {
    FacesContext context = FacesContext.getCurrentInstance();
    String id = event.getComponent().getClientId(context);
    String[] tokens = id.split("[:]+");
    int qId = -1;
    int subqId = -1;
    int sub2qId = -1;
    for (int i = 0; i < tokens.length; i++) {
        if(tokens[i].equals("questionTable")) 
            qId = Integer.parseInt(tokens[i+1]);
        if(tokens[i].equals("subQuestionTable"))
            subqId = Integer.parseInt(tokens[i+1]);
        if(tokens[i].equals("sub2QuestionTable"))
            sub2qId = Integer.parseInt(tokens[i+1]);

    }
    Question q = questions.getQuestion(qId);
    Question processQ = q;
    String defaultSubAnswer = getDefaultSubAnswer(q.getField());
    Question subq;
    Question subq2;
    if(subqId > -1) {
        subq = q.getAddnQuestions().get(subqId);
        processQ = subq;
        if(sub2qId > -1) {
            subq2 = subq.getAddnQuestions().get(sub2qId);
            processQ = subq2;
        }
    }
    resetValue(processQ, defaultSubAnswer);
}


private void resetValue(Question q, String defaultSubAnswer) {
    q.setAddnInfo("");
    if(q.getAddnQuestions() != null) {
        for (int i = 0; i < q.getAddnQuestions().size(); i++) {
            Question subq = q.getAddnQuestions().get(i);
            subq.setAnswer(defaultSubAnswer);
            resetValue(subq, defaultSubAnswer);
        }
    }
}

Вот проблема:

Событие ajax должно по умолчанию иметь значение valueChange. Если я нажму «Да», а затем снова «Да», вызов ajax не произойдет, правильно? Но это так, поскольку окно «Дополнительная информация» очищается на основе функции сброса.

Первоначально я пытался добавить условие в функцию сброса, чтобы проверить значение нажатой кнопки и сбросить значение и подзапросы addnInfo, только если ответ «0» (Нет). Но это вызывало проблемы с рендерингом, поскольку при вызове ajax окно ввода и подзапросы скрывались, а значение сохранялось на внешнем интерфейсе, даже если они сбрасывались на компоненте поддержки. При повторном рендеринге вперед, значение, которое было удержано, отображается вместо значения в компоненте поддержки.

Другой попыткой было использование ValueChangeListener для сброса значений. Но это все еще имеет ту же проблему со значением, удерживаемым при повторном рендеринге.

Я испробовал 3 разных подхода (перечислены выше), и все они провалились. Я открыт для решения любого из этих или, возможно, другого решения. Имейте в виду, что ограничения форматирования пользователями оставляют мне меньше возможностей для работы.

1 Ответ

4 голосов
/ 29 ноября 2011

Значение события Ajax Listener, похоже, вызывает onClick вместо onChange

Это действительно событие valueChange по умолчанию, которое используется переключателями и флажками, которые генерируются соответствующими компонентами JSF. Проверьте сгенерированный исходный код HTML, и вы увидите, что он подключен к onclick. Причина, по которой JSF делает это по умолчанию, ясна для флажков, но на первый взгляд не совсем понятна для переключателей, так как они все равно не могут быть отмечены. Настоящая причина в том, что это сделано для того, чтобы обеспечить совместимость с IE6 / 7, так как onchange не будет запускаться при первом нажатии в этом браузере.

Если вас не интересуют пользователи IE6 / 7 (чье распространение, однако, в последнее время сильно уменьшается), вместо этого измените его на event="change".

<f:ajax event="change" ... />

Таким образом, JSF сгенерирует обработчик событий на onchange.


Обновление : вы можете использовать jQuery .on('change') связыватель функций, который исправит неправильное поведение IE6 / 7 в событии change. Включите в <h:head> следующее, если вы еще не используете jQuery:

<script src="http://code.jquery.com/jquery-latest.min.js"></script>

и выполнить эту функцию при загрузке:

$(function() {
    $(':radio').each(function() {
        var handler = this.onclick;
        this.onclick = null;
        $(this).on('change', handler);
    });
});

Это будет в основном для каждой переключающей кнопки перемещать сгенерированный JSF атрибут onclick в обработчик событий change, которым управляет jQuery, чтобы он работал согласованно во всех браузерах, включая IE6 / 7.

Конечно, мы можем сделать это и с простым JS, но для этого потребуется много стандартного кода и кода, чувствительного к кроссбраузерности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...