Registering JS to HTML elements

After an exceedingly long break, I’m back working on Thedorus, so here’s a rather technical bit on what I’m currently doing.

As I’ve mentioned in the past, I don’t like Angular. My distaste for it and alike comes from their heresy of writing javascript code within the html code. I think it’s an incredibly wrong idea as it bind the code to a specific HTML, it duplicates code maintenance in case you have several HTML versions (themes for example) and it make the work of the HTML coder (assuming it’s not the JS-programmer himself) much more difficult as he needs to edit the HTML without stepping on any mine.

My alternative comes in two steps. First, I have my template-engine – O.
It’s works like mustache.js, only it serves my needs – it can easily use sub-templates and it has iterations, conditionals and even translation-support.
So running my engine would produces me a beautiful page, but I still need to integrate the JS-code somehow, right?
So my second step is to identify all the elements in the HTML that requires binding. I’ve marked them with the css-class “js-registry” and if they don’t have and ID they would also require the attribute “data-register” with the corresponding registry code (explained in a second).
But I said “no messing with the HTML”, right? well, I lied, but let’s go through this. An HTML element has 3 attribute that can be used as an identifier – the tag name, the element id and CSS class.
The tag (e.g. “<ol>” for ordered-list or “<u>” for unordered-list) should not be referred by either CSS or JS as we never know when it might change. CSS classes are obviously used for CSS. I should mention I despise people who use css-classes such as “text-align-center”. I mean, seriously? if you’re deciding the style at the HTML level why not use <center> tag and get it over with? CSS classes should not be indicative of the style content rather than the style function (e.g. “message-title” or “sign-up-button”)
Element-IDs, which are unique per page are for the sole use of JS and it’s a great way to find elements. But in the case you have a list of generic items (a list of message for example) that needs to be referred from the JS, then (and only then) I find it acceptable to use css-classes in the JS. But to make it clear for the HTML-coder that these classes are for the use of the JS (and he might end up losing a finger if he dare to temper with them), we can add the prefix “js-“, so in our example we’ll have “js-register”.
my code has a singleton “registry” code that contains the functions to be applied on the different DOM elements. So let’s say I have a DOM element with the ID “messageList”. If I’ll try to register it, I’ll find the pre-stored function that would fetch me the list using AJAX and then place them in the DOM document. Once messageList is registered, I would also look for any descendants and thus I’ll find myself registering all the messages as well.
I should mention that when registering the descendants, I’ll only registered this whose CSS-display style attribute isn’t set to ‘none’. That way, I won’t fetch any unnecessary information which I might not need. However when resizing the window, I’ll be sure to look again for elements that haven’t yet been registered. This functionality means that small-screen mobile won’t be bothered with loading elements they don’t need.
Using this registry system save me the need to be constantly vigilance for the case a button appears on the screen – meaning, I don’t need watchers, which are much-dreaded performance killers.
So I’m ok with intervening with the html and writing the “js-register” CSS-class name but bare in mind that this isn’t really a code, rather than a simple placeholder for code and it doesn’t affect the readability of the HTML code.
    this.onElementRegistered = (function onElementRegistered (elmId) {
        if (elmId !== undefined) {
            this.registerS(O.ELM.per('#'+elmId+' .js-register'));
        }
    }).bind(this);
    this.registerS = (function registerS (subElements) {
        var elmCount = subElements.length;
        while (elmCount--) {
            var dElm = subElements[elmCount];
            if (dElm.style.display !== 'none') {
                this.register(dElm);
            }
        }
    }).bind(this);
    this.register = (function register (dElm) {
        var dElmId = dElm.id;
        dElm.setAttribute('class',dElm.getAttribute('class').replace(/\bjs-register\b/,'js-registering'));
        var registerCode = dElm.getAttribute('data-register') || dElmId;
        if (this.registry[registerCode]) {
            this.registry[registerCode](dElm, this.onElementRegistered.bind(this,dElmId));
        }
        dElm.setAttribute('class',dElm.getAttribute('class').replace(/\bjs-registering\b/,'js-registered'));
    }).bind(this);
    this.onWindowResize = (function onWindowResize() {
        this.registerS(O.ELM.per('.js-register'));
    }).bind(this);
    window.onresize = O.EVT.subscribe('window.resize',this.onWindowResize).getDispatcher('window.resize');
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: