1

I'm not very good with JS. I am using this script on some textareas, successfully identified by class - http://www.jacklmoore.com/autosize/

My html looks like this for these textareas:

<textarea class="mst" id="name01" name="name01" placeholder="500 characters maximum" maxlength="500">Some text in here, up to 500 characters</textarea>

The size and look of the textarea is defined in css. Inside the page header I have this:

<script src="./js/textarea_autosize.js"></script>

Which is looks like this:

/*!
Autosize 3.0.14
license: MIT
http://www.jacklmoore.com/autosize
*/
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
    define(['exports', 'module'], factory);
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
    factory(exports, module);
} else {
    var mod = {
        exports: {}
    };
    factory(mod.exports, mod);
    global.autosize = mod.exports;
}
})(this, function (exports, module) {
'use strict';

var set = typeof Set === 'function' ? new Set() : (function () {
    var list = [];

    return {
        has: function has(key) {
            return Boolean(list.indexOf(key) > -1);
        },
        add: function add(key) {
            list.push(key);
        },
        'delete': function _delete(key) {
            list.splice(list.indexOf(key), 1);
        } };
})();

function assign(ta) {
    var _ref = arguments[1] === undefined ? {} : arguments[1];

    var _ref$setOverflowX = _ref.setOverflowX;
    var setOverflowX = _ref$setOverflowX === undefined ? true : _ref$setOverflowX;
    var _ref$setOverflowY = _ref.setOverflowY;
    var setOverflowY = _ref$setOverflowY === undefined ? true : _ref$setOverflowY;

    if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || set.has(ta)) return;

    var heightOffset = null;
    var overflowY = null;
    var clientWidth = ta.clientWidth;

    function init() {
        var style = window.getComputedStyle(ta, null);

        overflowY = style.overflowY;

        if (style.resize === 'vertical') {
            ta.style.resize = 'none';
        } else if (style.resize === 'both') {
            ta.style.resize = 'horizontal';
        }

        if (style.boxSizing === 'content-box') {
            heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
        } else {
            heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
        }
        // Fix when a textarea is not on document body and heightOffset is Not a Number
        if (isNaN(heightOffset)) {
            heightOffset = 0;
        }

        update();
    }

    function changeOverflow(value) {
        {
            // Chrome/Safari-specific fix:
            // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
            // made available by removing the scrollbar. The following forces the necessary text reflow.
            var width = ta.style.width;
            ta.style.width = '0px';
            // Force reflow:
            /* jshint ignore:start */
            ta.offsetWidth;
            /* jshint ignore:end */
            ta.style.width = width;
        }

        overflowY = value;

        if (setOverflowY) {
            ta.style.overflowY = value;
        }

        resize();
    }

    function resize() {
        var htmlTop = window.pageYOffset;
        var bodyTop = document.body.scrollTop;
        var originalHeight = ta.style.height;

        ta.style.height = 'auto';

        var endHeight = ta.scrollHeight + heightOffset;

        if (ta.scrollHeight === 0) {
            // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
            ta.style.height = originalHeight;
            return;
        }

        ta.style.height = endHeight + 'px';

        // used to check if an update is actually necessary on window.resize
        clientWidth = ta.clientWidth;

        // prevents scroll-position jumping
        document.documentElement.scrollTop = htmlTop;
        document.body.scrollTop = bodyTop;
    }

    function update() {
        var startHeight = ta.style.height;

        resize();

        var style = window.getComputedStyle(ta, null);

        if (style.height !== ta.style.height) {
            if (overflowY !== 'visible') {
                changeOverflow('visible');
            }
        } else {
            if (overflowY !== 'hidden') {
                changeOverflow('hidden');
            }
        }

        if (startHeight !== ta.style.height) {
            var evt = document.createEvent('Event');
            evt.initEvent('autosize:resized', true, false);
            ta.dispatchEvent(evt);
        }
    }

    var pageResize = function pageResize() {
        if (ta.clientWidth !== clientWidth) {
            update();
        }
    };

    var destroy = (function (style) {
        window.removeEventListener('resize', pageResize, false);
        ta.removeEventListener('input', update, false);
        ta.removeEventListener('keyup', update, false);
        ta.removeEventListener('autosize:destroy', destroy, false);
        ta.removeEventListener('autosize:update', update, false);
        set['delete'](ta);

        Object.keys(style).forEach(function (key) {
            ta.style[key] = style[key];
        });
    }).bind(ta, {
        height: ta.style.height,
        resize: ta.style.resize,
        overflowY: ta.style.overflowY,
        overflowX: ta.style.overflowX,
        wordWrap: ta.style.wordWrap });

    ta.addEventListener('autosize:destroy', destroy, false);

    // IE9 does not fire onpropertychange or oninput for deletions,
    // so binding to onkeyup to catch most of those events.
    // There is no way that I know of to detect something like 'cut' in IE9.
    if ('onpropertychange' in ta && 'oninput' in ta) {
        ta.addEventListener('keyup', update, false);
    }

    window.addEventListener('resize', pageResize, false);
    ta.addEventListener('input', update, false);
    ta.addEventListener('autosize:update', update, false);
    set.add(ta);

    if (setOverflowX) {
        ta.style.overflowX = 'hidden';
        ta.style.wordWrap = 'break-word';
    }

    init();
}

function destroy(ta) {
    if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
    var evt = document.createEvent('Event');
    evt.initEvent('autosize:destroy', true, false);
    ta.dispatchEvent(evt);
}

function update(ta) {
    if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
    var evt = document.createEvent('Event');
    evt.initEvent('autosize:update', true, false);
    ta.dispatchEvent(evt);
}

var autosize = null;

// Do nothing in Node.js environment and IE8 (or lower)
if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
    autosize = function (el) {
        return el;
    };
    autosize.destroy = function (el) {
        return el;
    };
    autosize.update = function (el) {
        return el;
    };
} else {
    autosize = function (el, options) {
        if (el) {
            Array.prototype.forEach.call(el.length ? el : [el], function (x) {
                return assign(x, options);
            });
        }
        return el;
    };
    autosize.destroy = function (el) {
        if (el) {
            Array.prototype.forEach.call(el.length ? el : [el], destroy);
        }
        return el;
    };
    autosize.update = function (el) {
        if (el) {
            Array.prototype.forEach.call(el.length ? el : [el], update);
        }
        return el;
    };
}

module.exports = autosize;
});

At the bottom of the page I have this:

</body>
<script type="text/javascript">
autosize(document.querySelectorAll('textarea.mst'));
</script>
</html>

It works perfectly when characters are typed into the textareas defined by class="mst", or characters from preloaded text are removed. However something must be added to or removed from the textareas for it to recognise the resize function and kick it into effect. Is there a simple way I can have each of the 10 textareas triggering on load, to match what they may have within them at the time of loading?

Please excuse my very bad understanding of JS, this might be a very simple question.

df0
  • 29
  • 5
  • Apologies - my link to the JS file was not working earlier so I have now put the entire file into my question above so it's easy to see. – df0 Nov 17 '15 at 03:39

2 Answers2

0

Have you tried window.onload

window.onload = function() {
    autosize(document.querySelectorAll('textarea.mst'));
};

This will wait until the full page is loaded before executing the autosize function. Based on what you have given, I am not sure what the problem is, but in my experience, when something doesn't fire like I expect, using window.onload = function(){ /*function to execute*/ }; helps.

Another option might be to trigger a change event on each textarea. This is described here.

I would use a for loop:

window.onload = function() {
    var toBeResized = document.querySelectorAll('textarea.mst');

    for (var i = 0, l = toBeResized.length; i < l; i++) {
        toBeResized[i].dispatchEvent(new Event(Event.CHANGE, true));
    }
};

Sources for the second solution to try are here and here

I hope either of these methods help.

Community
  • 1
  • 1
jay
  • 177
  • 1
  • 12
  • Hello jay, I have just tried your suggestion by placing your suggested code first at the bottom of the page under the `autosize(document.querySelectorAll('textarea.mst'));` and reloaded. It did not work, so I then tried it up within the header, still with the same result. – df0 Nov 16 '15 at 22:21
  • Jay, I'm really not getting any change in trying out these ideas, but I can see where you're trying to make it work. The problem (I believe) is that the function I have is not actually designed to contend with text already within the textarea so has no (apparent) function to consider this. Trying to get the function to fire on loading is not working, I _think_ because it really requires something like a keypress within the textarea focus... perhaps. Kinda grasping at straws here though... – df0 Nov 17 '15 at 03:32
  • @df0, I wonder if you iterated through your textarea elements and removed all the text, stored it to a variable, then added the text right back to the textarea, if that would help. There is no keypress there, so that may not work. I guess I am grasping at straws too. :) – jay Nov 17 '15 at 13:45
  • It's a good idea though, however how to try that out in JS is way beyond anything I know how to do. I thought I was clever just to get the thing to work with selected textareas by adding the class element to it and not have it working on all of them! ;-) – df0 Nov 17 '15 at 21:28
  • the above `window.onload = function() {` loops through them all within that loop, `var text = toBeResized[i].value;` `toBeResized[i].value = "";` `toBeResized[i].value = text;` that will alter the textarea value, but fill it back in with the original text, and hopefully trigger an autoresize. – jay Nov 18 '15 at 15:07
  • but glad you got it figured out! – jay Nov 18 '15 at 15:12
0

I discovered that the answer to this SO question works for my question as well. It utilises a different approach but achieves the correct end result.

Resize text area to fit all text on load jquery

Community
  • 1
  • 1
df0
  • 29
  • 5