SetPropertyActionListener в командной ссылке не работает

В таблице данных отображаются записи, которые я намерен редактировать. Для этого я использую командную ссылку, чтобы открыть диалоговое окно. setPropertyActionListener устанавливает объект CostingType, который должен иметь возможность изменяться из диалогового окна. Однако диалоговое окно не может получить переменные объекта или сохранить их. Вместо этого он показывает пустой объект, а нажатие на кнопку редактирования (после ввода полей) вместо этого показывает предупреждения requiredMessage. checkEdit() (который существует исключительно для целей отладки) также не вызывается.

HTML:

<h:form id = "costingTypeForm" >
<p:tabView id = "tabView">
<p:tab id = "tab1" title = "Costing Type">
<h:form id = "costingTypeForm" >              
                <p:tabView id = "tabView">
                <p:tab id = "tab1" title = "Costing Type">                                          
                    <p:dataTable
                            id = "costingTypeTable"
                            value = "#{costingTypeBean.costingTypeList}"
                            var = "costingType"
                            rows = "#{psmsProp['psms.dataTable.rows']}"
                            paginator = "true"
                            paginatorTemplate = "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown} {CurrentPageReport}"
                            rowsPerPageTemplate = "#{psmsProp['psms.dataTable.rowsPerPage']}"
                            currentPageReportTemplate = "Displaying {startRecord}-{endRecord} out of {totalRecords}"
                            style = "width:80%; text-align:center;"
                            sortBy = "#{costingType.name}"
                            sortMode = "single" >

                            <f:facet name = "header">  
                                Costing Type

                                <p:commandButton
                                    value = "Add"
                                    oncomplete = "PF('addCostingTypeDialog').show()"
                                    update = "costingTypeForm:tabView:addCostingTypeForm"
                                    icon = "ui-icon-plus"
                                    style = "float:right;" />

                                <div style = "clear:both" />  
                            </f:facet> 
                            <p:column sortBy = "#{costingType.name}"
                                filterBy = "#{costingType.name}"
                                filterMatchMode = "contains"
                                filterFunction = "#{filterUtil.containsFilter}"
                                filterStyle = "width:80%;"
                                headerText = "Name">
                                <p:outputLabel id = "name" value = "#{costingType.name}"  />
                            </p:column>                                             
                            <p:column headerText = "Description">
                                <p:outputLabel id = "description" value = "#{costingType.nameDesc}"  />
                            </p:column>
                            <p:column headerText = "Budgeted">
                                <p:outputLabel value = "Yes" rendered = "#{costingType.budget}" />
                                <p:outputLabel value = "No" rendered = "#{not costingType.budget}" />
                            </p:column>
                            <p:column headerText = "Deleted">
                                <p:outputLabel value = "Yes" rendered = "#{costingType.del}" />
                                <p:outputLabel value = "No" rendered = "#{not costingType.del}" />
                            </p:column>             
                            <p:column>
                                <p:commandLink
                                    oncomplete = "PF('editCostingTypeDialog').show()"
                                    update = ":costingTypeForm:tabView:editCostingTypeForm"
                                    value = "Edit" action = "#{costingTypeBean.checkEdit}">
                                    <f:setPropertyActionListener target = "#{costingTypeBean.editCostingType}" value = "#{costingType}"/>
                                </p:commandLink>                                    
                            </p:column>                                 
                            </p:dataTable>                              
                         <p:dialog
                            header = "Edit Costing Type"
                            widgetVar = "editCostingTypeDialog"
                            modal = "true"
                            showEffect = "slide"
                            hideEffect = "fade"
                            resizable = "false"
                            closable = "false">
                            <p:outputPanel id = "editCostingTypeForm">
                                <p:panelGrid columns = "2" cellpadding = "5" rendered = "#{not empty costingTypeBean.editCostingType}">                                       
                                    <h:panelGroup>
                                        <p:outputLabel value = "Name:" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:inputText value = "#{costingTypeBean.editCostingType.name}" required = "true" requiredMessage = "Name is required" />

                                    <h:panelGroup>
                                        <p:outputLabel value = "Description:" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:inputText value = "#{costingTypeBean.editCostingType.nameDesc}" required = "true" requiredMessage = "Description is required" />

                                    <p:outputLabel value = "Budgeted:" />
                                    <p:selectOneMenu value = "#{costingTypeBean.editCostingType.budget}">
                                        <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                        <f:selectItem itemValue = "false" itemLabel = "No" />
                                    </p:selectOneMenu>

                                    <h:outputLabel value = "Deleted:" />
                                    <p:selectOneMenu value = "#{costingTypeBean.editCostingType.del}">
                                        <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                        <f:selectItem itemValue = "false" itemLabel = "No" />
                                    </p:selectOneMenu>
                                </p:panelGrid>                                  
                                <p:commandButton
                                    value = "Cancel"
                                    actionListener = "#{costingTypeBean.cancelChange}"
                                    oncomplete = "PF('editCostingTypeDialog').hide();"
                                    icon = "ui-icon-close"
                                    style = "float:right;margin-top:10px;margin-bottom:10px;" />                                  
                                <p:commandButton
                                    value = "Edit"
                                    actionListener = "#{costingTypeBean.updateCostingType}"
                                    oncomplete = "if (args.update) PF('editCostingTypeDialog').hide();"
                                    update = ":costingTypeForm:messages @(.ui-datatable)"
                                    icon = "ui-icon-disk"
                                    style = "float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />
                            </p:outputPanel>
                        </p:dialog>
<p:dialog
                            header = "Add New CostingType"
                            widgetVar = "addCostingTypeDialog"
                            modal = "true"
                            showEffect = "slide"
                            hideEffect = "fade"
                            resizable = "false"
                            closable = "false">
                            <p:outputPanel id = "addCostingTypeForm">
                                <p:panelGrid columns = "2" cellpadding = "5">
                                    <h:panelGroup>
                                        <p:outputLabel value = "Name" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:inputText value = "#{costingTypeBean.name}" required = "true" requiredMessage = "Enter name" />                                        
                                    <h:panelGroup>
                                        <p:outputLabel value = "Description:" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:inputText value = "#{costingTypeBean.nameDesc}" required = "true" requiredMessage = "Enter Engine Type" />
                                    <h:panelGroup>
                                        <h:outputLabel value = "Budgeted:" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:selectOneRadio value = "#{costingTypeBean.budgeted}">
                                        <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                        <f:selectItem itemValue = "false" itemLabel = "No" />
                                    </p:selectOneRadio>
                                    <h:panelGroup>
                                        <h:outputLabel value = "Deleted:" />
                                        <p:outputLabel value = "*" style = "color:red;" />
                                    </h:panelGroup>
                                    <p:selectOneRadio value = "#{costingTypeBean.deleted}">
                                        <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                        <f:selectItem itemValue = "false" itemLabel = "No" />
                                    </p:selectOneRadio>
                                </p:panelGrid>
                                <p:commandButton
                                    value = "Cancel"
                                    actionListener = "#{costingTypeBean.cancelChange}"
                                    oncomplete = "PF('addCostingTypeDialog').hide();"

                                    icon = "ui-icon-close"
                                    style = "float:right;margin-top:10px;margin-bottom:10px;" />                                  
                                <p:commandButton
                                    value = "Save"
                                    actionListener = "#{costingTypeBean.addCostingType}"
                                    oncomplete = "if (args.add) PF('addCostingTypeDialog').hide(); else PF('addCostingTypeDialog').show();"
                                    update = "@form @(.ui-datatable)"
                                    icon = "ui-icon-disk"
                                    style = "float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />

                            </p:outputPanel>
                        </p:dialog> 
</p:tab>                                        
                       </p:tabView>
</h:form>

Фасоль поддержки:

@Component
 @Scope("view")
 public class CostingTypeBean{

private static final Logger LOGGER = LoggerFactory.getLogger(CostingTypeBean.class);

private long costingTypeId;    
private boolean budgeted, deleted;          
private String name, nameDesc;

private CostingType costingType; 
private CostingType editCostingType;

private List<CostingType> costingTypeList;

@Autowired
private CostingTypeService costingTypeService;

/*
getters and setters
*/
// dialog edit
public void updateCostingType(ActionEvent event) {
        RequestContext context = RequestContext.getCurrentInstance();

        if (editCostingType!=null) {
            costingTypeService.saveOrUpdate(editCostingType);
            context.addCallbackParam("update", true);
        }

        else
            context.addCallbackParam("update", false);
 }

 //debug method
 public void checkEdit() {
    LOGGER.debug("Edit listener");
    ViewUtil.showInfo("Edit dialog triggered");
    System.out.println("Edit listener");
}

Что я должен сделать, чтобы editCostingTypeDialog отражал поля объекта CostingType и мог читать значения, введенные в области ввода текста?

Получает ли editCostingType значение после нажатия на commandLink или оно равно нулю?

Holger 21.01.2019 15:58

@Holger Это ноль

nullpointer 21.01.2019 16:14

Тогда я восстановлю свой ответ, за который проголосовали. Было бы неплохо, если бы вы проголосовали за это, если это полезно для вас.

Holger 21.01.2019 16:23

Я только что протестировал <f:setPropertyActionListener в своей таблице данных. Он не должен отправлять null на ваш setEditCostingType(). Но он вызывается послеcheckEdit окружающего commandLink. Если вы нажмете второй раз, ваш editCostingType не должен быть нулевым. Это бесполезно, но вы можете проверить это.

Holger 22.01.2019 09:27

@Holger ActionListener не вызывается после действия.

Adam Waldenberg 24.01.2019 01:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
706
2

Ответы 2

Это ошибка в PrimeFaces (я думаю). Я искал много тестов в минимальном тестовом приложении. Невозможно использовать следующее созвездие:

<p:dataTable value = "#{bean.list}" var = "myVar".....
  <p:ajax event = "rowSelect" partialSubmit = "true" process = "@this" listener = "#{bean.doWork(myVar)}"/>

bean.doWork() всегда будет вызываться с нулевым указателем.

Стеклянная рыба 4.1.1 ПраймФейс 6.2

Я думаю, что ваша проблема такая же.

Это не так. Приведенный выше код из OP отлично работает с несколькими незначительными изменениями.

Adam Waldenberg 18.01.2019 14:22

Это мило. Я с нетерпеньем жду твоего ответа. Может мне тоже поможет.

Holger 18.01.2019 14:32

Пример кода делает почти то же самое; Primefaces.org/showcase/ui/data/datatable/selection.xhtml Однако правильное использование здесь заключается в том, чтобы выполнять listener = "#{bean.doWork}" и вместо этого обрабатывать SelectEvent (что включает в себя больше информации, чем просто отправка var. OP выполняет <f:setPropertyActionListener target = "#{costingTypeBean.editCostingType}" value = "#{costingType}"/>. Это совершенно правильно и должно (и работает) работать нормально.

Adam Waldenberg 21.01.2019 19:08

Да, вы правы, я пробовал. Я вставил <p:commandButton value = "Button" actionListener = "#{testbean.selWork()}" ajax = "true" partialSubmit = "true" process = "@this"> <f:setPropertyActionListener target = "#{testbean.selected}" value = "#{item}"/> </p:commandButton> в свою таблицу данных, и setSelected() вызывается со значением. Но он называется послеactionListener кнопки...?

Holger 22.01.2019 09:18

Правильный. Слушатели действий (включая прослушиватели действий свойств) обрабатываются первыми и в том порядке, в котором они были добавлены в компонент. Сначала вы определяете actionListener компонента. Если вы хотите получить доступ к набору свойств через f:setPropertyActionListenerиз события/действия кнопки - используйте action=. Слушатели действий следует использовать для обработки настройки состояний и/или проверок валидации (поскольку они могут прервать основное действие). Используйте атрибут действия для вызова бизнес-логики.

Adam Waldenberg 22.01.2019 11:25

Ваш код работает просто отлично. Все, что мне нужно было сделать, это изменить некоторые атрибуты update= (поскольку я получал исключения о том, что компоненты назначения не были найдены). После заполнения некоторыми случайными данными и использования приведенного выше кода я получаю следующее:

Я тестировал PrimeFaces 6.1 и 6.2 на Mojarra 2.3.3.99. Обратный вызов вспомогательного компонента для кнопки редактирования в диалоговом окне также вызывается правильно.

Итак, следующее, что нужно проверить — какую реализацию JSF вы используете? Это Мохарра или MyFaces? какая версия ? Возможно, вы столкнулись с какой-то ошибкой в ​​​​своей конкретной реализации. В вашем коде нет абсолютно ничего плохого.

Пока я этим занимаюсь, я мог бы опубликовать полный код (включая мои модификации);

<?xml version = "1.0" encoding = "UTF-8"?>
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html"
      xmlns:p = "http://primefaces.org/ui" xmlns:f = "http://java.sun.com/jsf/core">
    <h:head>
        <title>Costing type Test</title>
    </h:head>
    <h:body>
        <h:form id = "costingTypeForm" >              
            <p:tabView id = "tabView">
                <p:tab id = "tab1" title = "Costing Type">                                          
                    <p:dataTable
                        id = "costingTypeTable"
                        value = "#{costingTypeBean.costingTypeList}"
                        var = "costingType"
                        paginator = "true"
                        style = "width:80%; text-align:center;"
                        sortMode = "single" >

                        <f:facet name = "header">  
                            Costing Type
                            <p:commandButton value = "Add" oncomplete = "PF('addCostingTypeDialog').show()" update = "@form" icon = "ui-icon-plus" style = "float:right;" />
                            <div style = "clear:both" />  
                        </f:facet> 
                        <p:column sortBy = "#{costingType.name}"
                              filterBy = "#{costingType.name}"
                              filterMatchMode = "contains"
                              filterFunction = "#{filterUtil.containsFilter}"
                              filterStyle = "width:80%;"
                              headerText = "Name">
                            <p:outputLabel id = "name" value = "#{costingType.name}"  />
                        </p:column>                                             
                        <p:column headerText = "Description">
                            <p:outputLabel id = "description" value = "#{costingType.nameDesc}"  />
                        </p:column>
                        <p:column headerText = "Budgeted">
                            <p:outputLabel value = "Yes" rendered = "#{costingType.budget}" />
                            <p:outputLabel value = "No" rendered = "#{not costingType.budget}" />
                        </p:column>
                        <p:column headerText = "Deleted">
                            <p:outputLabel value = "Yes" rendered = "#{costingType.del}" />
                            <p:outputLabel value = "No" rendered = "#{not costingType.del}" />
                        </p:column>             
                        <p:column>
                            <p:commandLink
                                oncomplete = "PF('editCostingTypeDialog').show()"
                                update = ":costingTypeForm:tabView:editCostingTypeForm"
                                value = "Edit" action = "#{costingTypeBean.checkEdit}">
                                <f:setPropertyActionListener target = "#{costingTypeBean.editCostingType}" value = "#{costingType}"/>
                            </p:commandLink>                                    
                        </p:column>                                 
                    </p:dataTable>                              
                    <p:dialog
                        header = "Edit Costing Type"
                        widgetVar = "editCostingTypeDialog"
                        modal = "true"
                        showEffect = "slide"
                        hideEffect = "fade"
                        resizable = "false"
                        closable = "false">
                        <p:outputPanel id = "editCostingTypeForm">
                            <p:panelGrid columns = "2" rendered = "#{not empty costingTypeBean.editCostingType}">                                       
                                <h:panelGroup>
                                    <p:outputLabel value = "Name:" />
                                    <p:outputLabel value = "*" style = "color:red;" />
                                </h:panelGroup>
                                <p:inputText value = "#{costingTypeBean.editCostingType.name}" required = "true" requiredMessage = "Name is required" />

                                <h:panelGroup>
                                    <p:outputLabel value = "Description:" />
                                    <p:outputLabel value = "*" style = "color:red;" />
                                </h:panelGroup>
                                <p:inputText value = "#{costingTypeBean.editCostingType.nameDesc}" required = "true" requiredMessage = "Description is required" />

                                <p:outputLabel value = "Budgeted:" />
                                <p:selectOneMenu value = "#{costingTypeBean.editCostingType.budget}">
                                    <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                    <f:selectItem itemValue = "false" itemLabel = "No" />
                                </p:selectOneMenu>

                                <h:outputLabel value = "Deleted:" />
                                <p:selectOneMenu value = "#{costingTypeBean.editCostingType.del}">
                                    <f:selectItem itemValue = "true" itemLabel = "Yes" />
                                    <f:selectItem itemValue = "false" itemLabel = "No" />
                                </p:selectOneMenu>
                            </p:panelGrid>                                  
                            <p:commandButton
                                value = "Cancel"
                                actionListener = "#{costingTypeBean.cancelChange}"
                                oncomplete = "PF('editCostingTypeDialog').hide();"
                                icon = "ui-icon-close"
                                style = "float:right;margin-top:10px;margin-bottom:10px;" />                                  
                            <p:commandButton
                                value = "Edit"
                                actionListener = "#{costingTypeBean.updateCostingType}"
                                oncomplete = "if (args.update) PF('editCostingTypeDialog').hide();"
                                update = "@form"
                                icon = "ui-icon-disk"
                                style = "float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />
                        </p:outputPanel>
                    </p:dialog>
                </p:tab>                                        
            </p:tabView>
        </h:form>
    </h:body>
</html>

А вот вспомогательный компонент (в примере используются Lombok и Apache Commons);

@Data
@Named
@ViewScoped
public class CostingTypeBean implements Serializable {
    private CostingType costingType;
    private CostingType editCostingType;
    private List<CostingType> costingTypeList;

    @PostConstruct
    private void init() {
        costingTypeList = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            final String name = RandomStringUtils.randomAlphanumeric(10);
            final String nameDesc = RandomStringUtils.randomAlphanumeric(10);
            final boolean budget = RandomUtils.nextBoolean();
            final boolean del = RandomUtils.nextBoolean();

            costingTypeList.add(new CostingType(name, nameDesc, budget, del));
        }
    }

    public void updateCostingType(ActionEvent event) {
        System.out.println("update!");
    }

    public void checkEdit() {
        System.out.println("Edit listener");
    }

    public void cancelChange() {
        System.out.println("Cancel");
    }

    @Data
    @AllArgsConstructor
    public class CostingType {
        private String name;
        private String nameDesc;
        private boolean budget;
        private boolean del;
    }
}

Надеюсь, это может помочь.

Я использую Primefaces 5.2, Hibernate 4.2.6 и Spring 3.2.5. Больше всего в этом разочаровывает то, что кажется, что все в порядке, но это не работает.

nullpointer 21.01.2019 07:26

@NicholasLeong Вам придется сравнивать документы .. Если вы посмотрите на свой пример, вы определяете h:form и p:tab несколько раз в верхней части документа XHTML. Но я предполагаю, что это может быть опечатка? В остальном я особо не изменился. В основном незначительные изменения, чтобы заставить его работать с поддерживающим компонентом. Моя версия работает для вас? С PrimeFaces 5.2 не пробовал. Так может быть, это вызывает ваши проблемы?

Adam Waldenberg 21.01.2019 18:42

@NicholasLeong Вызов обновления из ссылки редактирования в таблице (update = ":costingTypeForm:tabView:editCostingTypeForm"), который повторно выбирает значения вспомогательного компонента в диалоговом окне, идентичен ... Я подозреваю, что виноват либо PrimeFaces 5.x, либо ваша версия / реализация JSF.

Adam Waldenberg 21.01.2019 19:14

Я наткнулся на то, что вызывало проблему. У меня был второй диалог (addCostingTypeDialog), в котором в двух полях были required и requiredMessage. Первоначально я думал, что часть html не имеет отношения к делу, поэтому я пропустил ее, но я просто вставил ее обратно. Удаление этих модификаторов решило проблему. Спасибо за попытку.

nullpointer 30.01.2019 09:29

Другие вопросы по теме