Module was briefly introduced in post 2 — it's a required XML file, and it forms the non-static part of the page. A module consists of Dvl'epr components, HTML structure for the UI, and SQL where it's needed. Here's a brief overview of how the module file pulls it together.

1 The module, wiring it all together

Every module follows one fixed skeleton, regardless of what it contains: a <module> root, a mandatory <layout> with an exact contentcontent-innerpage1page1a nesting, and one firm rule — every modal-form registration lives inside the modal overlay's id="bcmodal" container, never mixed in with ordinary page content. Here's that skeleton filled in with the four pieces from this arc:

emxml_modManagerContacts.xml
<module menu="no" navbar="no">
    <scripts></scripts>
    <links></links>
    <navbar/>
    <modulemenu></modulemenu>
    <submodmenu></submodmenu>
    <layout>

        <div class="content">
            <div class="content-inner">

                <!-- 1. MODAL OVERLAY — every modal form registration lives here -->
                <div class="modal-overlay" id="bcmodaloverlay">
                    <div class="modal modal-lg" id="bcmodal">

                        <!-- the form from posts 6 and 7 -->
                        <ajax type="html" name="addcontactform" for="bcmodal" modal="Y"
                              app="bcforms" submod="newcontactform"
                              responseid="CONTACTADDED"
                              onsuccess="getcontactslist" />

                    </div>
                </div>
                <!-- /modal overlay -->

                <!-- 2. PAGE CONTENT — header, list/table pane, detail pane from posts 3, 4 and 5 -->
                <div id="page1">
                    <div id="page1a">

                        <!-- page header: title, List/Table tabs, Add Contact button -->
                        <div class="page-header">
                            <div class="page-title">Contacts</div>
                            <div class="view-toggle">
                                <span class="active" onclick="getcontactslist()">List</span>
                                <span onclick="getcontactstable()">Table</span>
                            </div>
                            <button class="add-btn" onclick="getaddcontactform()">+ Add Contact</button>
                        </div>

                        <div class="split">

                            <!-- list/table pane — List renders by default; the Table tab above
                                 re-fetches the SAME container with post 4's file instead -->
                            <div id="contactsViewPane">
                                <block name="contactslist" file="emxml_blkContactsList.xml" />
                            </div>

                            <!-- detail pane, rendered on page load for the first contact -->
                            <div id="contactDetailPane">
                                <block name="contactdetail" file="emxml_blkContactDetail.xml" />
                            </div>

                        </div>

                        <!-- AJAX registrations: generate getcontactslist(), getcontactstable(), getcontactdetail(id) -->
                        <ajax type="html" name="contactslist" for="contactsViewPane"
                              app="ajaxblocks" module="managerblocks" submod="getcontactslist" />
                        <ajax type="html" name="contactstable" for="contactsViewPane"
                              app="ajaxblocks" module="managerblocks" submod="getcontactstable" />
                        <ajax type="html" name="contactdetail" for="contactDetailPane"
                              app="ajaxblocks" module="managerblocks" submod="getcontactdetail"
                              params="contact_id" />

                    </div>
                </div>

            </div>
        </div>

    </layout>
</module>

As you can see, a module is an XML document like all the others in this arc — and almost all of it is just HTML. There is no container element type to learn: a <div> is a <div>, a <button> is a <button>, and the tag you write is the tag that renders. Only two things above are not plain HTML:

  • <block file="…"/> — pulls in a block file and renders it here, on page load. That's how the list and detail panes get their initial content.
  • <ajax type="html" name="x" for="y"> — registers a piece of AJAX. Each one generates a getX() JavaScript function that fetches content and drops it into the element named by for=. This is the whole reason onclick="getcontactstable()" works above: nobody wrote that function.

Two details in those registrations are worth pointing out, because both replace code that used to be written by hand:

  • params="contact_id" names the token a value arrives as. getcontactdetail(42) sends contact_id=42, and the detail block's own SQL reads it as %contact_id%. Get that name wrong and the block's query silently sees an unresolved token instead of an id — so the name in params= and the name in the SQL always have to be the same word.
  • onsuccess="getcontactslist" is the entire post-save callback. modal="Y" already closes the modal on a matching response, and the success toast is on by default (dispmsg="N" turns it off), so the only thing left to say is which panel to refresh.

Every form and component this module uses is registered right here, in one place — which means anyone can see exactly what belongs to this page just by scanning the registrations, without digging through rendered output to work it out.

And if you look at the rendered version further down, every piece of HTML you see there traces straight back to something in the module file above.

2 Where this sits in the four-layer chain

From post 2 — every screen on the platform resolves through the same four layers. Here's where each piece from this arc actually lives:

APP
emxml_appManager.xml
The Manager role shell
SITE
emxml_siteManager.xml
Header, nav, and the modules list
MODULE
emxml_modManagerContacts.xml
The wiring shown above
BLOCKS
blkContactsList / Table / Detail, ajxInpFcontact
The four files this arc built
3 Rendered live — the whole thing
app.example.com/manager/contacts
S
Sarah Whitfield
Operations Manager
D
David Okonkwo
Procurement Lead
M
Maria Santos
Finance Controller
P
Priya Anand
Customer Service
Sarah Whitfield
Operations Manager · Operations
Emails.whitfield@example.com
Phone+44 1895 700 142
Open Orders3
Customer SinceMar 2023
Click a row, getcontactdetail(id) refreshes the right-hand pane. Click Add Contact, the form from post 6 opens and, on save, getcontactslist() refreshes the left-hand list. Two generated function calls are doing all of the interactivity on this page.

What actually got built across this arc

  • A list (post 3) — dynamiclist, free-form rows, one query.
  • A table (post 4) — dynamiclisttable, the structured alternative, same data.
  • A detail screen (post 5) — block-level SQL, single row, no row template.
  • A form (post 6) — validation, submit wiring, all generated from one registration.
  • A processor (post 7) — an insert, a response, an onsuccess handler with nothing left to hand-wire.
  • This page (post 8) — the same four-layer chain from post 2, holding all of it together.

Every piece here is real, working XML and SQL — not a simplified teaching example bearing only a passing resemblance to what you'd actually ship. This is what a small feature looks like on Dvl'epr, start to finish, in eight posts and considerably less code than it would have taken to hand-write the equivalent AJAX, validation, and DOM wiring yourself.

That's the full loop.

Read, browse, drill in, write back — the same handful of element types cover almost everything a business application needs to do. If you've followed this arc from post 1, you've now seen the platform's actual mechanics, not just the pitch for them.