В таблице данных отображаются записи, которые я намерен редактировать. Для этого я использую командную ссылку, чтобы открыть диалоговое окно. 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
и мог читать значения, введенные в области ввода текста?
@Holger Это ноль
Тогда я восстановлю свой ответ, за который проголосовали. Было бы неплохо, если бы вы проголосовали за это, если это полезно для вас.
Я только что протестировал <f:setPropertyActionListener
в своей таблице данных. Он не должен отправлять null на ваш setEditCostingType()
. Но он вызывается послеcheckEdit
окружающего commandLink. Если вы нажмете второй раз, ваш editCostingType не должен быть нулевым. Это бесполезно, но вы можете проверить это.
@Holger ActionListener не вызывается после действия.
Это ошибка в 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 отлично работает с несколькими незначительными изменениями.
Это мило. Я с нетерпеньем жду твоего ответа. Может мне тоже поможет.
Пример кода делает почти то же самое; Primefaces.org/showcase/ui/data/datatable/selection.xhtml Однако правильное использование здесь заключается в том, чтобы выполнять listener = "#{bean.doWork}"
и вместо этого обрабатывать SelectEvent
(что включает в себя больше информации, чем просто отправка var
. OP выполняет <f:setPropertyActionListener target = "#{costingTypeBean.editCostingType}" value = "#{costingType}"/>
. Это совершенно правильно и должно (и работает) работать нормально.
Да, вы правы, я пробовал. Я вставил <p:commandButton value = "Button" actionListener = "#{testbean.selWork()}" ajax = "true" partialSubmit = "true" process = "@this"> <f:setPropertyActionListener target = "#{testbean.selected}" value = "#{item}"/> </p:commandButton>
в свою таблицу данных, и setSelected()
вызывается со значением. Но он называется послеactionListener
кнопки...?
Правильный. Слушатели действий (включая прослушиватели действий свойств) обрабатываются первыми и в том порядке, в котором они были добавлены в компонент. Сначала вы определяете actionListener компонента. Если вы хотите получить доступ к набору свойств через f:setPropertyActionListener
из события/действия кнопки - используйте action=
. Слушатели действий следует использовать для обработки настройки состояний и/или проверок валидации (поскольку они могут прервать основное действие). Используйте атрибут действия для вызова бизнес-логики.
Ваш код работает просто отлично. Все, что мне нужно было сделать, это изменить некоторые атрибуты 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. Больше всего в этом разочаровывает то, что кажется, что все в порядке, но это не работает.
@NicholasLeong Вам придется сравнивать документы .. Если вы посмотрите на свой пример, вы определяете h:form
и p:tab
несколько раз в верхней части документа XHTML. Но я предполагаю, что это может быть опечатка? В остальном я особо не изменился. В основном незначительные изменения, чтобы заставить его работать с поддерживающим компонентом. Моя версия работает для вас? С PrimeFaces 5.2 не пробовал. Так может быть, это вызывает ваши проблемы?
@NicholasLeong Вызов обновления из ссылки редактирования в таблице (update = ":costingTypeForm:tabView:editCostingTypeForm"
), который повторно выбирает значения вспомогательного компонента в диалоговом окне, идентичен ... Я подозреваю, что виноват либо PrimeFaces 5.x, либо ваша версия / реализация JSF.
Я наткнулся на то, что вызывало проблему. У меня был второй диалог (addCostingTypeDialog
), в котором в двух полях были required
и requiredMessage
. Первоначально я думал, что часть html не имеет отношения к делу, поэтому я пропустил ее, но я просто вставил ее обратно. Удаление этих модификаторов решило проблему. Спасибо за попытку.
Получает ли
editCostingType
значение после нажатия на commandLink или оно равно нулю?