Styling form elements and trying to get around pitfalls

Greetings to readers, the stylized elements of the form on websites are now firmly entrenched in the realities of modern design and whoever says anything, in many cases they look really nice.
Many of you have already acquired plugins like chosen and other good, some of them are very well written. In this article I will not talk about the next plugin, but only want to draw your attention to one of the ways to expand the capabilities of the plugin, maybe it will help someone.
I am a supporter that when connecting plugins for styling forms, we must continue to work with form elements in the native style and not depend on the styling plugin. I practically didn’t see a correct plug-in for changing the behavior of elements when changing the attributes of the DOM elements of any plug-in (namely, handling of the attribute disabled ( min, max, maxlength ), I always had to take into account api plug-ins, layout of the element and so on, and this is inconvenient if in the future you want to change the plugin or layout. As an option, think in advance and make wrappers for everything and work with them as an internal api. But there is an alternative way.


Having studied the problem with attributes, it involuntarily comes to my mind - “but should we start to catch changes in the attributes of the element?” Having paid attention to MutationObserver and consulted caniuse , I understand that it’s time: crome, firefox have been supporting for a long time, the new IE11, too, is slowly crawling, and ios fully supports already. The result is the following code ( jsFiddle )

var MO = (window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver);
var observer = new MO(function(){ console.log("disabled changed") });
observer.observe(document.querySelector("id"), { attributes: true, attributeFilter: ["disabled"] });

It’s already good to only overcome IE, and here everything is bad ... First going - well, there is DOMAttrModified , as well as for very old propertychange .
Of course there are, they even work, but not in our case: events on a zadizeyblenny element do not throw. From here we get an interesting picture: when you add the disabled attribute, events are silent as partisans, while deleting, they quietly roll over. I would call it a bug rather than standard behavior, as the event is discordant and chopping everything off is bad, but what can I do. However, this does not stop us from writing a mini workaround for this problem ( jsFiddle )

var AttributeObserver = function(element, callback, attribute){
    var MO = (window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver);
    if (MO) {
        var observer = new MO(callback);
        observer.observe(element, { attributes: true, attributeFilter: [attribute] });
    } else {
        if (!AttributeObserver.__timer) {
            AttributeObserver.__observed = []
            AttributeObserver.__timer = setInterval(function(){
                for (var i = 0; i < AttributeObserver.__observed.length; i++) {
                    var o = AttributeObserver.__observed[i];
                    if (o.element.hasAttribute(o.attribute) !== o.flag) {
                        callback()
                    }
                    o.flag = o.element.hasAttribute(o.attribute)
                }
            }, 500)
            AttributeObserver.__observed.push({
                element: element,
                attribute: attribute,
                flag: element.hasAttribute(attribute)
            })
        }
    }
}

Anticipating the indignation of some people about setInterval, I’ll explain: no, this is not a hack, setInterval is quite a working construction of the language, which, with a reasonable approach, does not bring chaos and brakes, if you look at the real situation, then a reasonable interval would be 500-1000ms, and if you allow that there are usually 10-20 controls on the page, and even if 100 checks their attribute - there is no problem.
Also, this method is applicable for cases if you need to respond to changes in maxlength, min, max and other attributes that can affect the behavior of custom controls. The same min, max attributes for range input, if you work with native range input and do fallback for browsers without support, will look good with a similar approach to observing attributes and this can solve many problems - you work with input in its native form, and the plugin picks up the changes. I would like to consider this option now, because here we have an important problem - we are not working with disabled elements, which means we can upgrade our solution ( jsFiddle )

var AttributeObserver = function(element, callback, attribute){
    var MO = (window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver);
    if (MO) {
        var observer = new MO(callback);
        observer.observe(element, { attributes: true, attributeFilter: [attribute] });
    } else if (element.addEventListener) {
        element.addEventListener('DOMAttrModified', function(e){
            if (e.attrName == attribute) {
                callback()
            }
        }, false);
    } else if ("onpropertychange" in document) {
        element.attachEvent ('onpropertychange', function(e){
            if (e.attrName == attribute) {
                callback()
            }
        });
    }
}

PS I would like to add that the code does not pretend to be a finished plug-in, but rather just demonstrates one of the possible approaches.

Also popular now: