Search code examples
javascriptbigcommerce

How to detect input value length using MutationObserver


I need to make a text input field (phone number) length of at least 10 digits during checkout using Bigcommerce. I am using MutationObserver and the input field is being observed but I can not detect the changes. Please see code below:

<script>
(function(win) {
    'use strict';
    
    var listeners = [], 
    doc = win.document, 
    MutationObserver = win.MutationObserver || win.WebKitMutationObserver,
    observer;
    
    function ready(selector, fn) {
        // Store the selector and callback to be monitored
        listeners.push({
            selector: selector,
            fn: fn
        });
        if (!observer) {
            // Watch for changes in the document
            observer = new MutationObserver(check);
            observer.observe(doc.documentElement, {
                childList: true,
                subtree: true
            });
        }
        // Check if the element is currently in the DOM
        check();
    }
        
    function check() {
        // Check the DOM for elements matching a stored selector
        for (var i = 0, len = listeners.length, listener, elements; i < len; i++) {
            listener = listeners[i];
            // Query for elements matching the specified selector
            elements = doc.querySelectorAll(listener.selector);
            for (var j = 0, jLen = elements.length, element; j < jLen; j++) {
                element = elements[j];
                // Make sure the callback isn't invoked with the 
                // same element more than once
                if (!element.ready) {
                    element.ready = true;
                    // Invoke the callback with the element
                    listener.fn.call(element, element);
                }
            }
        }
    }

    // Expose `ready`
    win.ready = ready;
            
})(this);

ready('#phoneInput', function(element) {
    // do something
    if (element.value.length < 10) {
        element.style.borderColor = 'red';
        return;
    }
    // otherwise, set it to green
    element.style.borderColor = 'green';
});   
</script>

The idea is that the user gets an alert if the input field value is less than 10 digits whenever the user finishes typing and places focus on a different field. Thank you in advance. Other ideas are welcome and appreciated.


Solution

  • You can achieve what you want without using the observer:

            ready('#phoneInput', function (element) {
                element.addEventListener("input", function (e) {
                    if (e.target.value.length < 10) {
                        element.style.borderColor = 'red';
                        return;
                    }
                    // otherwise, set it to green
                    element.style.borderColor = 'green';
                });
            });
    

    If you have to use the observer I would move your conditions setting the borderColor to your check func:

                            if (!element.ready) {
                                element.ready = true;
                                // Invoke the callback with the element
                                listener.fn.call(element, element);
                            } else {
                                // do something
                                if (element.value.length < 10) {
                                    element.style.borderColor = 'red';
                                    return;
                                }
                                // otherwise, set it to green
                                element.style.borderColor = 'green';
                            }
    

    and add and event listener to your ready section:

            ready('#phoneInput', function (element) {
                element.addEventListener("input", function (e) {
                    element.setAttribute("value", e.target.value)
                });
            });
    

    You will need to add attributes to your observer opts:

                        observer.observe(doc.documentElement, {
                            childList: true,
                            subtree: true,
                            attributes: true
                        });
    

    Note: I think this may be a duplicate of/similar issue to Detect input value change with MutationObserver - there may be a few useful suggestions that answer your question in that thread? :)