unibase.element

unibase.element is used to create a new DOM element and insert it into the DOM as the last child of the parent. It can be used as a replacement for some use cases of insertAdjacentHTML (‘beforeend’).

unibase.element returns the newly created element. Something that insertAdjacentHTML doesn’t do.

unibase.element uses an object to describe the new element rather than text that must be parsed. Essentially it is a wrapper around several low level javascript methods such as document.createElement().

Using an object rather than text eliminates the slower parsing step.

unibase.element takes 2 arguments: element type as a string, eg ‘td’ and an optional object that describes the initial state of the element:

  • parent: the parent element for the new element. The new element is attached as the last element in the parent (parent.appendChild()). eg parent: tr
  • attributes: an object with the attributes for the new element. eg attributes: {id: ‘roster’, data-year: 19}
  • classes: an array of classes to apply. eg classes: [“blue”, “data”]
  • styles: an object with extra styles to apply. Note that these are javascript styles camel case instead of the – separated css styles. eg styles: {backgroundColor: “#e8e8e8”, width: “1em”}
  • events: an array of objects describing events and handlers. eg events: [ {event: “click”, handler: () => dosomething()} ]

The code for the function is here:

       let element = (type, args) => {
                let el = document.createElement (type);
                if (args) {
                        if (args['attributes']) {
                                for (const prop in args['attributes']) {el.setAttribute (prop, args['attributes'][prop])};
                                }
                        if (args['classes']) {
                                args['classes'].forEach (c => el.classList.add (c));
                                }
                        if (args['styles']) {
                                for (const prop in args['styles']) {el.style[prop] = args['styles'][prop]};
                                }
                        if (args['events']) {
                                args['events'].forEach (ev => el.addEventListener (ev['event'], ev['handler']));
                                }
                        if (args['parent']) {
                                args['parent'].appendChild (el);
                                }
                        }
                return el;
                }

And here is a few examples from roster.js (part of trojan.zenucom.com):

row = unibase.element ('tr', {classes: ["center", "btransparent"], parent: tbody});
let selectTd = unibase.element ('td', {parent: row, attributes: {id: `staffContractHour${rowId}`}, classes: ["staffCell"]});
let select = unibase.element ('select', {parent: selectTd, attributes: {id: `staffContractChange${rosterRow.staffId}${rowId}`}, classes: ["roster_button"]});
for (let C in [" ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]) {
        unibase.element ('option', {parent: select, attributes: {value: C}}).textContent = C;
        }

unibase.element (
        'img',
        {       parent: currentCell,
                attributes: {id: `addRosters${current}`, src: "/images/add.png", title: "Add staff to this week"},
classes: ["button"], events: [ {event: "click", handler: () => roster.addRow (currentRosterId, currentYear, currentWeek, selectedState, selectedCluster, currentLocation)} ] } );

To me it is much easier to read and use. It is in line with programming with frameworks. It also has the advantage that there is no parsing step and that is where much of the speedup comes from.

For img, if title is give but no alt, then title is used as alt (but not the other way round).

One of the benefits of getting the created element as the return from the call is that you can use is like this:

unibase.element ('td', {attributes: {id: yearWeekLocationId, colspan: colspan}, classes: ["locationNameTitle"], parent: row}).textContent = rosterRow.workLocationName;

unibase.element (
        'td',
        {       parent: currentRow,
                attributes: {id: `date${currentRosterId}`, colspan: colspan},
                classes: ["weekName"]
                }
        ).innerHTML = `${month}<br><br>YEAR ${currentYear} WEEK ${currentWeek}`;

row = unibase.element ('tr', {classes: ["center", "btransparent"], parent: tbody});

And of course we can extend this easily just by adding extra attributes to the initialising object such as textContent.