2
votes

In my Spring Boot 2 project I have Thymeleaf fragments to generate form elements. For example:

<input th:replace="component/admin_form :: text (formElement = ${vm.getElementStatus()}, class='css-class-a'))" />

The code above generates a complex div block with label, input field and error block.

I would like to simplify this syntax. My idea was to create a custom dialect with a custom tag and write this:

<admin-form:text value="${vm.getElementLastName()}" class="css-class-a"/>

The second one is easier to read, it clearly indicates for the designers that this is a special element. Besides this, it would be easier to change themes as I only need to change the concrete fragment location in the tag processor and not hundreds of th:replace value.

It is also important that I don't want to build the complex html layout in the tag processor just want to somehow import a fragment. So designers can modify the html fragment without java code changes.

I was able to create the custom dialect and create the custom tag that generates a html block:

@Override
protected void doProcess(ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structureHandler) {
    final IModelFactory modelFactory = context.getModelFactory();
    final IModel model = modelFactory.createModel();

    model.add(modelFactory.createOpenElementTag("div", "class", "test"));
    model.add(modelFactory.createText("This is my custom element"));
    model.add(modelFactory.createCloseElementTag("div"));

    structureHandler.replaceWith(model, false);
} 

But I don't know how to import a fragment in my custom tag.

Is it possible anyhow?

1

1 Answers

0
votes

The doProcess of your <admin-form:text> tag could create a dummy tag with a th:replace attribute that includes the "complex input" fragment:

Map<String, String> attributes = new HashMap<>();
attributes.put("th:replace", "/pathToMyFragment/complexInput::myfragname");
IOpenElementTag newTag = modelFactory.createOpenElementTag("div", attributes, AttributeValueQuotes.DOUBLE, false);
model.replace(0, newTag);

or something similar (take care of closing the tag and so on).

The result would be to replace

<admin-form:text/>

with

<div th:replace="/pathToMyFragment/complexInput::myfragname"></div>

which in turn would be processed into the final HTML. If you need to keep the original tag attributes (like class="css-class-a") you can get them from the original tag with model.get(0).getAttributeMap() and add them as a local variable with structureHandler.setLocalVariable("originalAttributes", theAttributeMap); to use in the final fragment, for example.