Arhn - архитектура программирования

Представление JSF не обновляется с использованием AJAX

Я пытаюсь создать обновляемый графический интерфейс, используя JSF 2.2 и PrimeFaces 4.0. Моя проблема в том, что модель обновляется, но не вид.

Вот моя примерная страница. У него есть только кнопка, которая должна заставить две панели поменять местами:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui">
    <h:head/>
    <h:body>
        <h:form>
            <p:panelGrid id="grid">
                <p:row>
                    <p:column id="slot1" style="width: 100px; height: 100px">
                        <p:panel id="panel1" binding="#{test.panel1}" style="width: 100px; height: 100px"/>
                    </p:column>
                    <p:column id="slot2" style="width: 100px; height: 100px">
                        <p:panel id="panel2" binding="#{test.panel2}" style="width: 100px; height: 100px"/>
                    </p:column>
                </p:row>
            </p:panelGrid>

            <p:commandButton id="button2" value="Switch Panels">
                <p:ajax listener="#{test.onSwitchPanels(event)}" update="grid"/>
            </p:commandButton>
        </h:form>
    </h:body>
</html>

И класс Java:

@ManagedBean
@SessionScoped
public class Test {

Panel panel1 = new Panel();
Panel panel2 = new Panel();

public Test() {
    panel1.setHeader("Panel 1");
    panel2.setHeader("Panel 2");
}

public Panel getPanel1() {
    return panel1;
}

public void setPanel1(Panel panel) {
    this.panel1 = panel;
}

public Panel getPanel2() {
    return panel2;
}

public void setPanel2(Panel panel) {
    this.panel2 = panel;
}

public void onSwitchPanels(ActionEvent event) {
    Panel tmp = panel1;
    panel1 = panel2;
    panel2 = tmp;
}
}

Отладка показывает мне, что геттеры и сеттеры вызываются после onSwitchPanels() с правильными новыми значениями при нажатии кнопки. Но как я писал вид не обновляется. Это происходит только после ручного обновления страницы или следующего щелчка (который, конечно, возвращает модель в исходное состояние, но показывает переключенные панели). Я уже пробовал update="@form" и update="slot1 slot2" безуспешно...

25.11.2013

Ответы:


1

Этот код, честно говоря, WTF. Привязка экземпляров компонента пользовательского интерфейса к bean-компоненту с областью действия сеанса — это путь к неприятностям. Экземпляры компонента пользовательского интерфейса находятся именно в области запроса.

Даже если вы использовали bean-компонент с областью запроса, это не сработает без перестроения представления. Дерево компонентов пользовательского интерфейса создается при построении представления. Вы манипулируете ссылками на компоненты после создания представления и ожидаете, что изменения волшебным образом отразятся в дереве компонентов пользовательского интерфейса. Это неправда. Будут отражены только их атрибуты (таким образом, когда вы делаете, например, panel1.setHeader(panel2.getHeader()) и наоборот, это будет работать.

Не совсем понятно, почему вы думали в этом направлении. Как правило, вы должны динамически манипулировать моделью, а не представлением (компоненты пользовательского интерфейса не представляют модель, они представляют представление; создание их свойств модели/контроллера не делает его волшебным образом моделью). Один из самых простых способов — иметь список сущностей и представлять их в динамическом <p:dataGrid> вместо жестко запрограммированного <p:panelGrid>, посредством чего вы динамически устанавливаете желаемые атрибуты компонента на основе текущего итерируемого элемента модели.

Например. это

<h:form>
    <p:dataGrid value="#{bean.items}" var="item" columns="2">
        <p:column><p:panel header="#{item.header}" /></p:column>
    </p:dataGrid>
    <p:commandButton value="swap" action="#{bean.swap}" update="grid" />    
</h:form>

с этим в @ViewScoped(!) bean-компоненте:

private List<Item> items; // +getter

@PostConstruct
public void init() {
    items = new ArrayList<>();
    items.add(new Item("Panel 1"));
    items.add(new Item("Panel 2"));
}

public void swap() {
    items.add(items.remove(0)); // Note: works only if you've only 2 items ;)
}

Класс Item — это просто javabean со свойством header. Средняя IDE может автоматически генерировать весь класс.

Смотрите также:

25.11.2013
  • Большое спасибо. Я только прототипировал. Моя проблема в том, что для желаемой функциональности недостаточно изменить некоторые атрибуты. Я хочу иметь возможность иметь, например. панель с диаграммой, панель с текстом и некоторыми самостоятельно написанными компонентами, которые можно свободно переставлять в сетке. Если это можно сделать только путем перезагрузки представления, то так тому и быть. Но, возможно, JSF в любом случае не подходит для моего варианта использования... 26.11.2013
  • Если вы хотите условно построить представление вместо условного рендеринга представления, возьмите JSTL. 26.11.2013

  • 2

    Я немного заржавел в своем JSF/PF, но вы пробовали:

    update="panel1 panel2"
    

    Еще одна вещь, которую можно попробовать, это использовать

    actionListener"#{test.onSwitchPanels}"
    

    вместо

    listener="#{test.onSwitchPanels(event)}"
    
    25.11.2013
  • Я попробовал первый, но он не работал. Второе невозможно в p:ajax. 25.11.2013
  • Насколько мне известно, в JSF2.2/Primefaces 4 больше не нужно указывать p:ajax вручную, все компоненты с поддержкой ajax могут напрямую обновлять другие компоненты. Посмотрите здесь: primefaces.org/showcase-labs/ui/pprCounter.jsf 25.11.2013
  • Ах хорошо. Итак, я попробовал <p:commandButton id="button2" value="Switch Panels" actionListener="#{test.onSwitchPanels}" update="grid"/>, но результат тот же. (Для атрибута update я также пробовал @form, slot1 slot2 и panel1 panel2.) 25.11.2013
  • Аааа, я помню, что у меня была похожая проблема некоторое время назад. Это связано с жизненным циклом, в котором задействована «форма» (по сути, форма отправляет себя или что-то в этом роде и неправильно обновляет страницу). У меня нет с собой моего кода, чтобы увидеть, как именно я это исправил, но есть три вещи, которые вы можете попробовать сразу: 1. Добавьте id='myform' в тег формы и получите обновление для обновления. «myform», 2. создать новую форму и иметь «сетку» и «кнопку» в разных формах, 3. обернуть форму в панель и обновить всю панель. Если ничего из этого не сработает, сегодня вечером я откопаю свой старый код! 25.11.2013
  • Большое спасибо! Я попробовал все три совета, но ни один не сработал :( Было бы здорово, если бы вы нашли свое решение... 25.11.2013
  • Хорошо, я посмотрю, что я могу раскопать. Другая теория заключается в том, что фактические заполнители компонентов визуализируются на этапе жизненного цикла, отличном от «привязки». Я знаю, что это не так аккуратно, но вы могли бы попробовать поменять местами поля внутри каждой панели, а не менять местами целые панели? 25.11.2013
  • Это работает, если я просто поменяю местами тексты заголовков. Но это не вариант использования, который я имею в виду... 25.11.2013
  • Мне удалось найти копию моего старого кода в Интернете, хотя на данном этапе я не уверен, насколько он будет вам полезен (думаю, мы охватили все основы!), но мой работал так: form1, содержащий «gmap» с идентификатором «mygmap» и form2, содержащий commandButton с actionListener, который внес множество изменений в базовую модель, а затем использовал синтаксис -- update=:form1:mygmap -- для обновления ajax и обновите экран. Боюсь, я уже почти достиг предела своих знаний по этому вопросу :( 25.11.2013
  • (вы могли бы попробовать добавить немедленное значение = true в свой commandButton?) 25.11.2013
  • в JSF2.2/Primefaces 4 вам больше не нужно указывать p:ajax вручную Это не так. Это уже имело место в PF3 и относится только к UICommand компонентам. <p:ajax> по-прежнему необходим в UIInput компонентах. 25.11.2013

  • 3

    Почему бы не удалить параметр event из метода onSwitchPanels()? вы не используете его в любом случае. Вы могли бы запустить его

    <p:commandButton id="button2" value="Switch Panels" action="#{test.onSwitchPanels}" update="grid" />
    
    25.11.2013
  • просто интересно, так как мой ответ был выбран в течение 1-2 дней: сработало ли мое решение для вас? 29.11.2013

  • 4

    Я нашел решение, использующее этот пример: http://www.wobblycogs.co.uk/index.php/computing/jee/70-dynamic-dashboard-with-primefaces-part-2

    Суть в том, чтобы создавать компоненты программно. На странице JSF я просто пишу что-то вроде <p:panelGrid id="grid" binding="#{gridBacker.grid}"/> и использую bean-компонент для создания строк, столбцов и панелей с помощью Application.createComponent(). Затем панели снова добавляются после события.

    Так что, конечно, BalusC был прав, говоря, что действие должно происходить в модели.

    27.11.2013
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..