понедельник, 30 марта 2009 г.

Замена механизма отображения ошибок при валидации в Tapestry 5.1

При унифицированном подходе к отображению ошибок на форме, обычно для каждого поля ставится соответствующий html-элемент, либо элементы в которых пользователю сообщается об ошибке в конкретном поле. К примеру, в Spring-mvc в таком случае вам придется ставить тэг form:error для каждого поля.

Механизм отображения ошибок в Tapestry 5 реализован с помощью специального декоратора, который призван избавить разработчика от расставления подобных элементов на своей странице. Реализация этого механизма находится в классе org.apache.tapestry5.internal.DefaultValidationDecorator. Результат его работы выглядит так:

Согласитесь, не очень красиво вставлять красный крест после каждого поля с ошибкой да еще и подсвечивать его содержимое. Во всяком случае меня это не устроило. Хотелось бы, чтобы ошибки выглядели примерно так:

Для этого, в модуле tapestry вашего приложения необходимо подменить markup-фильтр DefaultValidationDecorator совоей реализацией:

package com.blogspot.nkoksharov.tapestry;

import org.apache.tapestry5.*;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.services.*;

public class AppModule {

public void contributeMarkupRenderer(OrderedConfiguration configuration,
final Environment environment) {

MarkupRendererFilter defaultValidationDecorator = new MarkupRendererFilter() {
public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) {
ValidationDecorator decorator = new ExValidationDecorator(environment, writer);
environment.push(ValidationDecorator.class, decorator);
renderer.renderMarkup(writer);
environment.pop(ValidationDecorator.class);
}
};

configuration.override("DefaultValidationDecorator", defaultValidationDecorator);
}
}

Логика декоратора выглядит так:

package com.blogspot.nkoksharov.tapestry;

import org.apache.tapestry5.*;
import org.apache.tapestry5.services.Environment;

public class ExValidationDecorator extends BaseValidationDecorator {

private static final String ERROR_ELEMENT_CLASS = "error_element";

private final Environment environment;
private final MarkupWriter markupWriter;

public ExValidationDecorator(Environment environment, MarkupWriter markupWriter) {
this.environment = environment;
this.markupWriter = markupWriter;
}

@Override
public void afterField(Field field) {
if (inError(field)) {
String errorId = field.getClientId() + "Error";
markupWriter.element("div",
"class", ERROR_ELEMENT_CLASS,
"id", errorId);
markupWriter.write(getErrorMsg(field));
markupWriter.end();
}
}

private String getErrorMsg(Field field) {
ValidationTracker tracker = environment.peekRequired(ValidationTracker.class);
return tracker.getError(field);
}

private boolean inError(Field field) {
ValidationTracker tracker = environment.peekRequired(ValidationTracker.class);
return tracker.inError(field);
}
}

Данный декоратор после каждого поля ставит такой вот элемент:

<div class="error_element" id="someElementError">
Сообщение об ошибке для данного поля
</div>

Стоит отметить, что возможность переопределения элементов в списке конфигурации сервисов, через метод override стала доступна лишь начиная с версии Tapestry 5.1.0.0