Reputation: 15834
Server-side dev here, looking to dabble in a bit of vanilla JS to learn the ropes.
This question is about creating a form where textareas
are initially hidden behind button clicks, and which also resize as the text entered into them grows larger. It's a challenging problem for someone at my level, and I'm trying to code it myself for learning purposes.
Here's what I've done so far.
Imagine a forum where users submit textual content. Each submission has a "reply" button under it. Pressing that opens a simple textarea
that one can type their response into. I wrote simple JS to accomplish this:
var replyBtns = document.querySelectorAll('[id=rep]');
for(var i = 0; i < replyBtns.length; i++) {
replyBtns[i].addEventListener('click', function(e) {
e.preventDefault();
var textarea = document.getElementById("reply-message");
if (textarea) { textarea.parentNode.removeChild(textarea); }
var replyBox = document.createElement('textarea');
replyBox.setAttribute('id', 'reply-message');
replyBox.setAttribute('placeholder', 'Reply');
this.parentNode.insertAdjacentElement('beforeend', replyBox);
}, false);
}
As you can see, this JS creates a text area and adds it in the HTML. The CSS to go with it is:
textarea#reply-message {
display: block;
border: none;
color:#306654;
font-size:120%;
padding: 5px 10px;
line-height: 20px;
width:550px;
height: 20px;
border-radius: 6px;
overflow: hidden;
resize: none;
}
This works well.
My next endeavour was to make this textarea
resize as the text starts overflowing. For that, I'm taking this route:
Grab the content loaded into the textarea
Create an invisible clone div
Give the clone the same width and typographical properties as the textarea
Place the content into the clone
Get the height of the clone
Apply the height of the clone to the height of the textarea
This strategy uses the property that any div
element naturally stretches to fit the height of its content (assuming no floats or absolutely positioned elements). I owe this technique to this blog post.
Here's the JS for implementing the aforementioned technique:
let txt = document.getElementById('reply-message'),
hiddenDiv = document.createElement('div'),
content = null;
hiddenDiv.classList.add('hiddendiv');
document.body.appendChild(hiddenDiv);
txt.addEventListener('keyup', function () {
content = this.value;
hiddenDiv.innerHTML = content + '\n\n';
this.style.height = hiddenDiv.getBoundingClientRect().height + 'px';
}, false);
Where hiddendiv
is:
.hiddendiv {
position: absolute;
left: -9999px;
visibility: hidden;
white-space: pre-wrap;
width: 550px;
height: 20px;
font-size: 120%;
padding: 5px 10px;
word-wrap: break-word;
overflow-wrap: break-word;
}
But thing is, I need this JS snippet to run only once the textarea
actually exists.
Currently, I have it running on page load, where it's unable to have any effect since textareas
don't yet exist. How do I ensure it only runs once they've been created? Being a newbie in JS, this is totally eluding me. Please advise.
Upvotes: 0
Views: 238
Reputation: 34137
There is plugin for that autosize
Check the src at github, you will get idea on how to do it.
If your code is working in page load and not in text update, you need to call your resize function in every keyup, resize and input events.
window.addEventListener('resize', yourFunc);
textarea.addEventListener('paste', yourFunc);
textarea.addEventListener('keyup', yourFunc);
There is simpler method here
function auto_grow(element) {
element.style.height = "5px";
element.style.height = (element.scrollHeight)+"px";
}
textarea {
resize: none;
overflow: hidden;
min-height: 50px;
}
<textarea onkeyup="auto_grow(this)"></textarea>
Upvotes: 0
Reputation: 10165
Maybe using a div with contenteditable
instead of a textarea would make your life a bit easier.
#textarea {
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
border: 1px solid gray;
padding: 2px;
width: 400px;
}
<div id="textarea" contenteditable>dummy textarea</div>
Upvotes: 0
Reputation: 450
This isn't exactly answering your question, but restructuring your code a bit to achieve the same result.
You should add the event listener to your textarea
when you create it, before you add it to the page.
Insert code like this in your first glob of javascript:
replyBox.setAttribute('placeholder', 'Reply');
replyBox.addEventListener('keyup', function () {
/* do event handling here */
}, false);
A cleaner way to handle all of this would be to move all of the code pertaining to setting up your textarea
s into a separate function.
function setUpReplyBox(replyBox) {
replyBox.setAttribute('id', 'reply-message');
replyBox.setAttribute('placeholder', 'Reply');
hiddendiv.createElement('div');
content = null;
hiddendiv.classList.add('hiddendiv');
document.body.appendChild(hiddenDiv);
replyBox.addEventListener('keyup', function () {
content = this.value;
hiddenDiv.innerHTML = content + '\n\n';
this.style.height = hiddenDiv.getBoundingClientRect().height + 'px';
}, false);
}
Call this right after you create the item, at
var replyBox = document.createElement('textarea');
setUpReplyBox(replyBox);
this.parentNode.insertAdjacentElement('beforeend', replyBox);
Upvotes: 1
Reputation: 1150
Listen for the domContentLoaded Event
document.addEventListener("DOMContentLoaded", function(event) {
console.log("DOM fully loaded and parsed");
});
Reference Link https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Upvotes: 0