0

So I have lets say N textarea elements in my webpage and I want to get the value of the textarea whenever user tries to type something into that. I wrote the code

<textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>

and the script is

document.addEventListener('DOMContentLoaded', function (){
        var textareas = document.getElementsByTagName("textarea");
        console.log(textareas.length);
        for(var i = 0; i<textareas.length; i++){
                textareas[i].onkeypress = function (){
                    console.log(textareas[i].value);
                }
        }
    });

the line console.log(textareas.length); is printing the value 3 but I don't understand why console.log(textareas[i].value); is throwing error

Uncaught TypeError: Cannot read property 'value' of undefined

I mean if textareas[i] is not defined for it then why textareas[i].onkeypress is working properly. If it is the wrong way how can I get the value of the respective textarea when user writes something on it.

viveksinghggits
  • 661
  • 14
  • 35
  • 4
    Just replace `console.log(textareas[i].value);` with `console.log(this.value);`. – blex Jul 10 '16 at 18:41
  • yeah that working fine, but the thing if `textarea[i]` doesnt exist then why is this working fine `textareas[i].onkeypress` – viveksinghggits Jul 10 '16 at 18:43
  • Defining functions in a for loop gives you that headaches. The iterator `i` won't be what you expect it to be inside the anonymous function. – 1sloc Jul 10 '16 at 18:45
  • it has to do with the `scope` of the object. Inside the `textareas` `onkeypress` event `this` will be the current context i.e `textareas`. Hence you have to use `this` to get the `textareas` object. – Venkata Dorisala Jul 10 '16 at 18:45
  • Because you defined a function inside of a loop, which does not work. This would work if you made the function outside of the loop then referenced it. – Makaze Jul 10 '16 at 18:46

5 Answers5

2

Best have an EventListener and assign the object itself with this because at some point you would want to remove.

document.addEventListener('DOMContentLoaded', function (){
    var textareas = document.getElementsByTagName("textarea");
    console.log(textareas.length);
    for(var i = 0; i<textareas.length; i++){
        textareas[i].addEventListener('keyup', function (){
            console.log(this.value);
        });
    }
});
Leroy Thompson
  • 470
  • 3
  • 13
1

Its because when you are clicking on that textarea, the value of i is equal 3. and textares[3] is undefined.

Hence its throwing this error.

You can solve that using e.target.value.

textareas[i].onkeypress = function (e){
                    console.log(e.target.value);
}
ankur kushwaha
  • 458
  • 3
  • 9
0
document.addEventListener('DOMContentLoaded', function () {
    var textareas = document.getElementsByTagName("textarea");
    for (var i = 0; i < textareas.length; i++) {
        !function (textarea) {
            textarea.onkeyup = function () {
                console.log(textarea.value);
            }
        }(textareas[i]);
    }
}, false);
Sagi
  • 8,972
  • 3
  • 33
  • 41
0

Because the scope changes from when you define your onkeypress handler to when it executes, the browser no longer knows what textareas[i] is. You need to bind that to your handler in the following manner:

document.addEventListener('DOMContentLoaded', function (){
        var textareas = document.getElementsByTagName("textarea");
        console.log(textareas.length);
        for(var i = 0; i<textareas.length; i++){
                textareas[i].onkeypress = function (){
                    console.log(this.value);
                }.bind(textareas[i])
        }
    });
<textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>

Bind is a tricky one, but learning it will solve so many gotchas in the long run: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


Also, you'll find you're missing the last character typed with your code as is. This is due to the handler firing on keydown (before the entry) as opposed to keyup. Try the following to capture the last character, too:

document.addEventListener('DOMContentLoaded', function (){
        var textareas = document.getElementsByTagName("textarea");
        console.log(textareas.length);
        for(var i = 0; i<textareas.length; i++){
                textareas[i].addEventListener('keyup', function(event) {
                    console.log(this.value);
                });
        }
    });
<textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>
        <textarea rows="10" cols="25">

        </textarea>
jmealy
  • 583
  • 1
  • 5
  • 14
  • The use of `bind` there is utterly pointless. The default value of `this` for an event listener is the element being listened on anyway. Your code does fix the problem, but your description of the solution is a massive red herring. The fix is using `this.value` instead of `textareas[i].value`. – Quentin Jul 10 '16 at 18:53
  • That's actually not correct. Your `this` statement is true and a good one, but my usage of `bind` is not incorrect. Try `textareas[i].onkeypress = function (){console.log(this.what);}.bind({el: textareas[i], what: 'the'})` and you'll see the affect. – jmealy Jul 10 '16 at 19:09
  • Why are you now passing an object to it? The version you had in your original answer was pointless. https://jsfiddle.net/90bptfph/ and https://jsfiddle.net/90bptfph/1/ behave identially. – Quentin Jul 11 '16 at 06:25
0

It is not working, because you define i outside of the inner function. i wil be textareas.length+1, and not the current textarea. What you can do is:

document.addEventListener('DOMContentLoaded', function (){
        var textareas = document.getElementsByTagName("textarea");
        console.log(textareas.length);
        for(var i = 0; i<textareas.length; i++){
                textareas[i].onkeypress = function (){
                //i is 4, so we have to use `this`:
                console.log(this.value)
                // console.log(textareas[i].value);
                }
        }
    });
Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117