Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Java |
![]() ![]() |
Aghial Member Откуда: Сообщений: 25 |
Добрый день Столкнулся с проблемой, при реализации на Primefaces с версиями <jsf.version>2.2.8</jsf.version> <primefaces.version>3.0</primefaces.version> динамического добавления и удаления компонентов inputTextarea с редактированием внутри них значений В итоге удалось реализовать более менее работающий макет, но столкнулся с трудностью- при редактировании значения - если тут же не убирая фокус добавить новый элемент - подтягивается предыдущее нередактированное значения. Приложил скрин с описанием проблемы Создал репо, в котором текущий код можно легко запустить используя mvn clean install run:jetty https://github.com/aradess/jsf-jetty-dyn Собственно вопрос, - каким должен быть код, чтобы редактирования и последующая вставка нового значения проходила корректно? <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <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" xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head> <title>PrimeFaces Hello World Example</title> </h:head> <h:body> <h:form> <p:panel id="main"> <h:panelGrid columns="2"> <h:outputText value="Add value" style="vertical-align: top; width: 200px;"/> <p:selectOneMenu widgetVar="type" id="type" style="width: 350px" value="#{helloWorld.selectedType}"> <f:selectItem itemValue="#{null}" itemLabel=""/> <f:selectItems value="#{helloWorld.availableFields}" var="def" itemLabel="#{def}" itemValue="#{def}"/> <p:ajax event="change" update="main" listener="#{helloWorld.change(helloWorld.selectedType)}"/>/> </p:selectOneMenu> </h:panelGrid> <h:panelGroup id="panelRepeatWrapper"> <c:forEach id="panelRepeat" items="#{helloWorld.selectedFields}" var="field"> <h:panelGrid columns="3"> <h:outputText value="#{field}" style="vertical-align: top; width: 200px;"/> <h:inputTextarea value="#{helloWorld.values[field]}" style="width: 550px; height: 50px;"/> <p:commandButton value="x" action="#{helloWorld.onDelete(field)}" update="main"> </p:commandButton> </h:panelGrid> </c:forEach> </h:panelGroup> </p:panel> </h:form> </h:body> </html> package groupid; import javax.annotation.PostConstruct; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.context.FacesContext; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @ManagedBean @SessionScoped public class HelloWorld { private final static List<String> ENTITIES = Arrays.asList(new String[]{"1", "2", "3", "4", "5"}); @PostConstruct public void init() { selectedFields = ENTITIES.stream().filter(s -> !"5".equals(s)).collect(Collectors.toSet()); availableFields = ENTITIES.stream().filter(s -> "5".equals(s)).collect(Collectors.toSet()); values.put("1", "1"); values.put("2", "2"); values.put("3", "3"); values.put("4", "4"); } private String selectedType = ""; private Set<String> availableFields; private Set<String> selectedFields; private Map<String, String> values = new HashMap<String, String>(); public Set<String> getAvailableFields() { return availableFields; } public void setAvailableFields(Set<String> availableFields) { this.availableFields = availableFields; } public Set<String> getSelectedFields() { return selectedFields; } public void setSelectedFields(Set<String> selectedFields) { this.selectedFields = selectedFields; } public Map<String, String> getValues() { return values; } public void setValues(Map<String, String> values) { this.values = values; } public void change(String type) { Optional<String> f = availableFields.stream().filter(s -> s.equals(type)).findFirst(); selectedFields.add(f.get()); availableFields.remove(f.get()); values.put(f.get(), null); } public void onDelete(String type) { Optional<String> f = selectedFields.stream().filter(s -> s.equals(type)).findFirst(); selectedFields.remove(f.get()); availableFields.add(f.get()); values.put(f.get(), null); } public String getSelectedType() { return selectedType; } public void setSelectedType(String selectedType) { this.selectedType = selectedType; } } К сообщению приложен файл. Размер - 30Kb |
6 авг 19, 15:44 [21943044] Ответить | Цитировать Сообщить модератору |
забыл ник Member Откуда: Сообщений: 3062 |
попробуй ui:repeat из facelets вместо c:forEach из jstl. Но я сильно не вчитывался, просто знаю что c:orEach хреновенько работает с динамически добавляемыми элементами |
6 авг 19, 15:49 [21943048] Ответить | Цитировать Сообщить модератору |
vas0 Member Откуда: Таможенный союз (Россия, Казахстан) Сообщений: 1291 |
JSTL по моему вообще не работает и вмести с JSF их лучше не использовать |
6 авг 19, 15:52 [21943053] Ответить | Цитировать Сообщить модератору |
Aghial Member Откуда: Сообщений: 25 |
пробовал ui:repeat - работоспособного варианта не получилось, то есть с c:forEach удалось продвинуться дальше, но попробую |
||
6 авг 19, 17:09 [21943127] Ответить | Цитировать Сообщить модератору |
Aghial Member Откуда: Сообщений: 25 |
vas0, совет по использованию JSTL был найден на stackoverflow, в то же время там была найден пост о различиях https://stackoverflow.com/questions/3342984/jstl-in-jsf2-facelets-makes-sense Проблема в том, что я практически не работал ранее с JSF и не хотелось бы собирать все его грабли Потому и прошу совета |
6 авг 19, 17:12 [21943132] Ответить | Цитировать Сообщить модератору |
Aghial Member Откуда: Сообщений: 25 |
Попробовал ui:repeat https://github.com/aradess/jsf-jetty-dyn/blob/feature/repeat/src/main/webapp/helloworld.xhtml https://github.com/aradess/jsf-jetty-dyn/blob/feature/repeat/src/main/java/groupid/HelloWorld.java Как бы работает, но это не то что нужно. Это все реализовано через события вида onclick=submit() - но это приводит к ререндерингу всей формы. А реальный кейс, в котором используется данная функциональность - сложнее, и ререндеринг в нем лишний. Попробую уточнить загвоздку, которую нужно решить, которая есть в следующем коде: Нужно чтобы при выборе значения в selectOneMenu и соответственно запуска в ajax listener="#{helloWorld.change(helloWorld.selectedType)}"/> , чтобы перед запуском этого listener значения которые введены в h:inputTextarea были синхронизированы с helloWorld.values[field] Потому что сейчас наблюдается ситуация: 1) Ввели значение в Поле 3 (и это никак не отобразилось на значениях в helloWorld.values) 2) Выбрали добавление элемента из выпадающего списка 3) Обновили элемент c id="main" значениями которые в helloWorld.values (а они устаревшие) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <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" xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head> <title>PrimeFaces Hello World Example</title> </h:head> <h:body> <h:form> <p:panel id="main"> <h:panelGrid columns="2"> <h:outputText value="Add value" style="vertical-align: top; width: 200px;"/> <p:selectOneMenu widgetVar="type" id="type" style="width: 350px" value="#{helloWorld.selectedType}"> <f:selectItem itemValue="#{null}" itemLabel=""/> <f:selectItems value="#{helloWorld.availableFields}" var="def" itemLabel="#{def}" itemValue="#{def}"/> <p:ajax event="change" update="main" listener="#{helloWorld.change(helloWorld.selectedType)}"/>/> </p:selectOneMenu> </h:panelGrid> <h:panelGroup id="panelRepeatWrapper"> <c:forEach id="panelRepeat" items="#{helloWorld.selectedFields}" var="field"> <h:panelGrid columns="3"> <h:outputText value="#{field}" style="vertical-align: top; width: 200px;"/> <h:inputTextarea value="#{helloWorld.values[field]}" style="width: 550px; height: 50px;"/> <p:commandButton value="x" action="#{helloWorld.onDelete(field)}" update="main"> </p:commandButton> </h:panelGrid> </c:forEach> </h:panelGroup> </p:panel> </h:form> </h:body> </html> |
7 авг 19, 15:09 [21943865] Ответить | Цитировать Сообщить модератору |
Alexander A. Sak Member Откуда: Омск Сообщений: 1040 |
Давно не трогал JSF, но вдруг угадаю. Добавить у p:ajax атрибут process="main" не пробовали? Вроде по умолчанию процессится только компонент, в котором расположен этот p:ajax. |
||
7 авг 19, 18:53 [21944103] Ответить | Цитировать Сообщить модератору |
olegeos Member Откуда: Сообщений: 166 |
А что такая старая версия primefaces? |
21 авг 19, 22:07 [21954883] Ответить | Цитировать Сообщить модератору |
olegeos Member Откуда: Сообщений: 166 |
<p:panel id="main2"> <h:panelGrid columns="2"> <h:outputText value="Add value" style="vertical-align: top; width: 200px;"/> <p:selectOneMenu widgetVar="type" id="type2" style="width: 350px" value="#{helloWorld.selectedType}"> <f:selectItem itemLabel=""/> <f:selectItems value="#{helloWorld.availableFields}" var="def" itemLabel="#{def}" itemValue="#{def}"/> <p:ajax event="change" update="main2" listener="#{helloWorld.change2()}"/>/> </p:selectOneMenu> </h:panelGrid> <p:panel id="panelRepeatWrapper2"> <ui:repeat id="panelRepeat1" value="#{helloWorld.listTextArea}" var="field" > <h:panelGrid columns="4"> <h:outputText value="#{field.nomerRow}" style="vertical-align: top; width: 200px;"/> <h:inputTextarea value="#{field.area}" style="width: 550px; height: 50px;"/> <p:commandButton id="button1" value="x" actionListener="#{helloWorld.onDelete2(field)}" update="form1:panelRepeatWrapper2" /> <p:message for="button1" showDetail="true" showSummary="true"/> </h:panelGrid> </ui:repeat> </p:panel> </p:panel> public class HelloWorld { private final static List<String> ENTITIES = Arrays.asList(new String[]{"1", "2", "3", "4", "5"}); private final String[] array = new String[]{"1", "2", "3", "4", "5"}; private List<TestList> listTextArea; @PostConstruct public void init() { selectedFields = ENTITIES.stream().filter(s -> !"5".equals(s)).collect(Collectors.toSet()); availableFields = ENTITIES.stream().filter(s -> "5".equals(s)).collect(Collectors.toSet()); values.put("1", "1"); values.put("2", "2"); values.put("3", "3"); values.put("4", "4"); //---------- listTextArea = new ArrayList<>(); } private String selectedType = ""; private Set<String> availableFields; private Set<String> selectedFields; private Map<String, String> values = new HashMap<>(); public Set<String> getAvailableFields() { return availableFields; } public void setAvailableFields(Set<String> availableFields) { this.availableFields = availableFields; } public Set<String> getSelectedFields() { return selectedFields; } public void setSelectedFields(Set<String> selectedFields) { this.selectedFields = selectedFields; } public Map<String, String> getValues() { return values; } public void setValues(Map<String, String> values) { this.values = values; } public void change(String type) { Optional<String> f = availableFields.stream().filter(s -> s.equals(type)).findFirst(); selectedFields.add(f.get()); availableFields.remove(f.get()); values.put(f.get(), null); } public void onDelete(String type) { Optional<String> f = selectedFields.stream().filter(s -> s.equals(type)).findFirst(); selectedFields.remove(f.get()); availableFields.add(f.get()); values.put(f.get(), null); } public void change2() { TestList ttt = new TestList(); ttt.setNomerRow("1"); ttt.setArea(selectedType); listTextArea.add(ttt); } public void onDelete2(TestList test) { if (!listTextArea.isEmpty()) { listTextArea.remove(test); System.out.println(listTextArea.size()); } } public String getSelectedType() { return selectedType; } public void setSelectedType(String selectedType) { this.selectedType = selectedType; } public List<TestList> getListTextArea() { return listTextArea; } public void setListTextArea(List<TestList> listTextArea) { this.listTextArea = listTextArea; } такой вариант |
21 авг 19, 23:44 [21954924] Ответить | Цитировать Сообщить модератору |
Aghial Member Откуда: Сообщений: 25 |
Прощу прощения за столь поздний ответ. Потому что это суровый legacy с кучей функциональности и без тестов. Поменять версию компонентов нереально |
||
26 авг 19, 00:16 [21957390] Ответить | Цитировать Сообщить модератору |
Aghial Member Откуда: Сообщений: 25 |
К сожалению у меня не взлетел. Были ошибки компиляции, исправил их, выложил код https://github.com/aradess/jsf-jetty-dyn/blob/feature/2/src/main/webapp/helloworld.xhtml По-прежнему была трабла: 1) Ввели новое значение в Поле 3 (и это никак не отобразилось на значениях в helloWorld.values) 2) Выбрали добавление элемента из выпадающего списка 3) После автоматического обновления значение в Поле 3 - старое, до редактирования Нашел, путем неоднократного гугления по разным запросам следующий пост https://stackoverflow.com/a/30216301 Предлагается использовать ajax и перехватывать значения в bean непосредственно из AjaxBehaviorEvent, и синхронизировать значение мапы в bean со значением, которое на экране Вроде бы заработало, буду смотреть дальше public void fieldValue(AjaxBehaviorEvent e) { if (e.getSource() instanceof UIInput) { UIInput input = (UIInput) e.getSource(); Object value = input.getValue(); String id = input.getId(); values.put(id.substring(2), value.toString()); } } https://github.com/aradess/jsf-jetty-dyn/tree/feature/AjaxBehaviorEvent |
||
26 авг 19, 02:00 [21957403] Ответить | Цитировать Сообщить модератору |
Все форумы / Java | ![]() |