webfirmframework for Java Experts

MLTP Architecture

MLTP stands for Model Logical-Template Push. The model (AKA domain object) gives the data required for logical-template. Logical Template could be a reusable custom template class containing wff java code which can generate a piece of html for the UI. Push, which is done by the framework internally itself when a template/layout is embedded by another template and we don't have to take care about the push part.


Logical-template

Logical-template is a reusable template class which can generate a specific portion of a ui with needful functionalities. The below code shows a simple example for Logical-template. The logical template may be provided model to show required data (it's not included in the below code but you can simply modify). The mere responsibility of a logical-template class is to generate a specific portion for ui with functionalities


public class ListUsersTempate extends Div implements ServerMethod {

    private static final Logger LOGGER = Logger.getLogger(ListUsersTempate.class.getName());

    private TBody tBody;

    private Collection previousRows;

    private int rowCount = 0;

    private Button nextRowsButton;

    private OnClick nextRowsButtonOnClick;

    private OnClick commonOnClick;

    private Button markGreenButton;

    private Button markVioletButton;

    private Button removeColoumnStyleButton;

    private final Style countryColumnStyle;

    public ListUsersTempate() {
        super(null);
        countryColumnStyle = new Style("background:yellow");
        develop();
    }

    private void develop() {

        new StyleTag(this).give(TagContent::text, """
                table {
                    font-family: arial, sans-serif; border-collapse: collapse;
                    width: 100%;
                }
                td, th {
                    border: 1px solid #dddddd;
                    text-align: left;
                    padding: 8px;
                }
                tr:nth-child(even) {
                    background-color: #dddddd;
                }
                """);

        new Table(this).give(table -> {
            tBody = new TBody(table).give(bdy -> {
                new Tr(bdy).give(tr -> {
                    new Th(tr).give(TagContent::text, "Company (会社)");
                    new Th(tr).give(TagContent::text, "Contact (接触)");
                    new Th(tr).give(TagContent::text, "Country (国)");
                });
            });
        });

        new Br(this);
        new Br(this);

        nextRowsButtonOnClick = new OnClick(this);
        commonOnClick = new OnClick(this);

        nextRowsButton = new Button(this, nextRowsButtonOnClick).give(btn -> {
            new B(btn).give(TagContent::text, "Next");
        });

        markGreenButton = new Button(this, commonOnClick).give(btn -> {
            new B(btn).give(TagContent::text, "Mark column green");
        });

        markVioletButton = new Button(this, commonOnClick).give(btn -> {
            new B(btn).give(TagContent::text, "Mark column violet");
        });

        removeColoumnStyleButton = new Button(this, commonOnClick).give(btn -> {
            new B(btn).give(TagContent::text, "Remove style from column");
        });

        // initially add rows
        addRows();
    }

    private void addRows() {

        Collection rows = new LinkedList();

        for (int i = 0; i < 25; i++) {

            Tr newTr = new Tr(null).give(tr -> {
                rowCount++;

                new Td(this).give(TagContent::text, "Alfreds Futterkiste " + rowCount);
                new Td(this).give(TagContent::text, "Maria Anders " + rowCount);
                new Td(this, countryColumnStyle).give(TagContent::text, "Germany " + rowCount);
            });

            rows.add(newTr);
        }

        if (previousRows != null) {
            tBody.removeChildren(previousRows);
        }

        tBody.appendChildren(rows);

        previousRows = rows;

    }

    @Override
    public WffBMObject invoke(Event event) {
        WffBMObject dataFromClient = event.data();

        // if nextRowsButtonOnClick is equal to event.getSourceAttribute()
        // then nextRowsButton will be equal to event.getSourceTag()
        // because nextRowsButtonOnClick attribute is added only in
        // nextRowsButton
        // But, in the case of commonOnClick it's added in
        // three buttons so the sourceTag must also be checked.

        if (nextRowsButtonOnClick.equals(event.sourceAttribute())) {

            addRows();

        } else if (commonOnClick.equals(event.sourceAttribute())
                && markGreenButton.equals(event.sourceTag())) {

            LOGGER.info("Mark column green");
            countryColumnStyle.addCssProperties("background:green");

        } else if (commonOnClick.equals(event.sourceAttribute())
                && markVioletButton.equals(event.sourceTag())) {

            LOGGER.info("Mark column violet");
            countryColumnStyle.addCssProperties("background:violet");

        } else if (commonOnClick.equals(event.sourceAttribute())
                && removeColoumnStyleButton.equals(event.sourceTag())) {

            LOGGER.info("remove style");
            AbstractHtml[] ownerTags = countryColumnStyle.getOwnerTags();

            for (AbstractHtml ownerTag : ownerTags) {
                ownerTag.removeAttributes(countryColumnStyle.getAttributeName());
            }
        }

        return null;
    }

}

Later you can add this template class to any specific portion of ui, eg:

ListUsersTempate listUsers = new ListUsersTempate();

//suppose you have a div in the ui to add, then

div.appendChild(listUsers);