Recently I’ve been noticing that tutorials supply code in it’s fully formed nature, leaving people confused about if they are expected to directly write code that works in the same way.
But, code doesn’t come from us as fully formed working code. It usually goes through a process of modification to make things work better.
I plan to use a series of posts here to demonstrate that code doesn’t normally start off great. Instead, it’s improved over time as it’s forced to work under different situations.
An initial attempt
A niave attempt to start off with is a count function that we plan to expand on:
<script>
function counter() {
console.log(this.value.length);
}
</script>
<p><textarea oninput="counter()"></textarea></p>
That doesn’t work though, because the inline oninput method doesn’t let the function know how it was called.
- Problem: Inline event handlers don’t communicate well with functions.
- Solution: Pass information to the function about what to work with.
Pass element reference to the function
Passing the this
keyword to the count function, gives a reference to the element letting us easily work with it.
function counter(textarea) {
console.log(textarea.value.length);
}
<p><textarea oninput="counter(this)"></textarea></p>
And it works. The browser console shows the updated character count when you edit the text in the textarea section.
But, we want that number to show on the screen beside the textarea.
We can add a span element to show the character count, and we’ll start by showing a default character limit of 50 characters:
<p>
<textarea oninput="counter(this)"></textarea>
<span id="counter">0</span>/50
</p>
Web browsers automatically let you access identified elements which we’ll use for now, but there are problems with that too. We’ll get those problems dealt with later.
We can now update the count function so that it updates the span element:
function counter(textarea) {
counter.innerHTML = textarea.value.length;
}
But that doesn’t quite work, because there’s a clash between the function name and the id attribute on the page.
- Problem: Element identifiers get clobbered by other variables.
- Solution: Use querySelector to refer to HTML elements.
Access element by reference
We can rename the function to countChars to resolve the conflict, but a more reliable solution is to use querySelector to gain a reference to the element. We’ll want to rename the function name too, to prevent the function name and the variable, so that they don’t end up clashing with each other too.
<script>
function countChars(textarea) {
const counter = document.querySelector("#counter");
counter.innerHTML = textarea.value.length;
}
</script>
<p>
<textarea oninput="countChars(this)"></textarea>
<span id="counter">0</span>/50
</p>
And that works, case closed.
Or it would be, but there are problems:
- countChars function assumes only one textarea
- inline attribute event handlers don’t belong in the HTML code
- The span counter is meaningless when scripting doesn’t work
In the following posts I’m going to change the situations in which the code must work, to force beneficial changes to the code.