public class MyObj
{
private boolean isEnable;
private boolean check1;
private BigDecimal money1;
private BigDecimal money2;
private Boolean check2;
}
Есть соответствующие им геттеры и сеттеры.
На странице в браузере должен быть список таких объектов в виде таблицы. В строках таблицы располагаются чекбоксы и инпуты для редактирования вышеперечисленных полей класса. При этом последние четыре поля должны быть доступны для редактирования (быть активными, проще говоря, незадизабленными), только если первое поле true, то есть стоит галочка в чекбоксе конкретной строки.
Соответственно, управлять активностью этих элементов надо при каждом изменении инпута, отвечающего за первое поле, плюс сразу после загрузки страницы, чтобы отобразить изначальное состояние. Первое, что приходит в голову - это доступ к полям объекта через ${someVar} для инициализации состояния контролов сразу после загрузки страницы, и яваскрипт на изменение контрола, замапленного на первое поле объекта.
Таблица на ZK, графические компоненты тоже из этого фреймворка. Если с яваскриптом, который отлавливает изменение состояния контрола, кое как через жопу справился (используются конструкции типа #{self.parent.parent.parent} - это я передаю компонент строки, в котором ищу все контролы, кроме первого, и дизаблю их, если надо, не забывая на лету править стили). То со вторым конкретно впал в ступор. На форуме проекта нашел, как сделать вызов яваскрипта после загрузки страницы, но использовать это нельзя как минимум из-за невозможности передачи динамических параметров. Во-вторых, из-за чрезмерной даже для ZK кривости.
Создал отдельную тему по вопросу, что же делать с инициализацией начального состояния контролов. Более менее приличного ответа нет. Только намек на то, чтобы все делать через сервер. То есть, кликнули на контрол - ушел запрос на сервер. Контрол потерял фокус - ушел запрос на сервер и т.д. Сегодня плюнул и сделал именно так. Через их интерфейс TypeConverter, который по идее создавался для удобного преобразования переданных в страницу данных. У меня же получилось полное уродство, "стучащая" на сервер на каждый onchange каждого контрола (строк на странице около сотни):
import org.zkoss.zkplus.databind.TypeConverter;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.api.HtmlBasedComponent;
import org.zkoss.zul.impl.api.InputElement;
import org.zkoss.zul.api.Checkbox;
import utils.CommonUtils;
import java.lang.reflect.Method;
/**
* В зависимости от значения поля isEnable объекта MyObj делает компонент инабленным или задизабленным.
* Если true, то компонент будет инбаленным, если false, то задизабленным.
* Сделано, потому что херов ZK не поддерживает выражения при динамическом биндинге.
* Также надо учитывать, что на каждое изменение значения флага будет запрос на сервер
*
* @author danilov
*/
public class DisableTypeConverter implements TypeConverter
{
/**
* Название аттрибута, показывающего, нужно ли дизаблить компонент
*/
public static final String FLAG_ATTR = "enabled";
/**
* Название аттрибута, в котором будет храниться изначальный объект, чтобы потом можно было бы его вернуть
*/
public static final String SAVE_ATTR = "saveValue";
/**
* Суффикс, который нужно приставить к стилю, чтобы элемент выглядел задизабленным
*/
public static final String DISABLED_SUFFIX = "_disabled";
/**
* Название аттрибута, в котором будет передано название поле, которое надо обслужить этим конвертером
*/
public static final String FIELD_ATTR = "field";
@Override
public Object coerceToUi( Object val, Component comp )
{
MyObj myObj = ( MyObj ) val;
boolean isBooleanType = false;
if( myObj != null )
{
HtmlBasedComponent htmlComp = ( ( HtmlBasedComponent ) comp );
if( htmlComp instanceof Checkbox )
{
isBooleanType = true;
}
if( !myObj.isEnable() )
{
//Ну не пиздец ли это???
if( htmlComp instanceof Checkbox )
{
( ( Checkbox )htmlComp ).setDisabled( true );
}
else
{
( ( InputElement ) htmlComp ).setDisabled( true );
}
htmlComp.setSclass( htmlComp.getSclass() + DISABLED_SUFFIX );
}
htmlComp.setAttribute( SAVE_ATTR, myObj );
String fieldName = ( String )comp.getAttribute( FIELD_ATTR );
//Если поле не указано, значит надо указать, так как без него работать не будет, а потому на исключение забиваем
try
{
Method method;
try
{
method = myObj.getClass().getMethod( CommonUtils.convertFieldNameToGetMethodN
}
catch( NoSuchMethodException e )
{
//видимо, булевский тип определили неправильно, так что попробуем еще раз
method = myObj.getClass().getMethod( CommonUtils.convertFieldNameToGetMethodN
}
return method.invoke( myObj );
}
catch( Exception ignored )
{
throw new RuntimeException( "Give me the right field name! Wrong field name: " + fieldName );
}
}
return myObj;
}
@Override
public Object coerceToBean( Object val, Component comp )
{
MyObj myObj = ( MyObj )comp.getAttribute( SAVE_ATTR );
String fieldName = ( String )comp.getAttribute( FIELD_ATTR );
//Если поле не указано, значит надо указать, так как без него работать не будет
try
{
Method method;
try
{
method = myObj.getClass().getMethod( CommonUtils.convertFieldNameToSetMethodN
}
catch( NoSuchMethodException e )
{
//видимо, булевский тип определили неправильно, так что попробуем еще раз
method = myObj.getClass().getMethod( CommonUtils.convertFieldNameToSetMethodN
}
method.invoke( myObj, val );
}
catch( Exception ignored )
{
throw new RuntimeException( "Give me the right field name! Wrong field name: " + fieldName );
}
return myObj;
}
}
Рефлексию прикрутил, чтобы не плодить четыре конвертера по одному на каждое поле. Хотя тут скорее всего ошибся, надо было слабать четыре. Точно получилось бы быстрее. А универсальности все равно нет - жесткая завязка на конкретный класс.
Работает. Точнее, будет работать, когда верстальщик переопределит стандартные стили ZK для задизабленых компонентов. А также есть мнение, что будет мигать после загрузки, то есть все контролы сначала будут активными, а потом по мере отрабатывания маппинга будут дизаблиться, если это нужно. Как сделать по-другому - хз, возможно, что никак.
Зато идеологически правильно - все же данные хранятся на сервере, значит изменять их можно только через сервер. Наверное, как-то так думали создатели этого нереального геморроя.
Думаю, я терпеливый человек, раз столько времени пытался найти нормальное решение, понял, что его нет, написал этот говнокод и при этом не расхуячил монитор и клавиатуру. Душевно спокойнее будет суп в дуршлаге сварить.
Или все-таки кто-нибудь может объяснить, в чем я не прав, за исключением использования рефлексии?
Пусть будет проклят тот день, когда я согласился использовать это чудовище ради одной красивой таблички...