1

I have a form on my website with several different textareas.

HTML/PHP

foreach ($bla as $blabla) {
  .... other php-code (not relevant) ....
  echo '<textarea id="textarea['.$blabla["ID"].']" name="textarea" maxlength="1000" onKeyUp="countChars(\'textarea['.$blabla["ID"].']\',\'count\',\'{CHAR}\',1000);""></textarea>';
  echo '<span id="counter">1000</span>';
}

JS:

function countChars(entrance, exit, text, characters) {
  var entranceObj = document.getElementById(entrance);
  var exitObj = document.getElementById(exit);
  var length = characters - idObj.value.length;
  if (length <= 0) {
    length = 0;
    text =
      '<span class="disable" style="color: red;">' +
      text +
      '</span>';
    entranceObj.value = entranceObj.value.substr(0, characters);
  } else if (length <= 20) {
    text =
      '<span style="color: red">' +
      text +
      '</span>';
  }
  exitObj.innerHTML = text.replace("{CHAR}", length);
}

This code works. However, the counter only works for one textarea. Any ideas why it isn't working on all?

leo
  • 91
  • 1
  • 10
  • 2
    please note, html elements must have a unique id, currently you are assigning `id="textarea"` to each element created in your loop. – GrafiCode May 07 '22 at 11:33
  • 1
    hence, this `var entranceObj = document.getElementById(entrance);` will always refer to the first textarea. – GrafiCode May 07 '22 at 11:34
  • 1
    you can assign different ids using a counter, like this: `foreach ($bla as $blabla) { $i++; echo ' – GrafiCode May 07 '22 at 11:36
  • @GrafiCode I've tried giving it different id's using "id=textarea[$blabla["ID"]]". I just don't know how to move on from there. – leo May 07 '22 at 11:36
  • 1
    ah ok then also modify this `onKeyUp="countChars(\'textarea[' . $blabla["ID"] . '] \', ....` – GrafiCode May 07 '22 at 11:38
  • @GrafiCode Tried that too. It doesn't work unfortunately. – leo May 07 '22 at 11:43
  • All textareas have the [same id](/q/5611963). This means you can only find the first one through `document.getElementById('textarea')`. And the [same name](/q/452066). This might also not be intended. – cachius May 07 '22 at 12:19

1 Answers1

1

You need to give unique identifiers for each textarea and counter span. Here's your PHP code modified to match (using heredoc string delimiters to keep it more readable):

foreach ($bla as $key => $blabla) {
    echo <<<BLA
<textarea id="textarea_{$key}" name="textarea_{$key}" maxlength="1000"
 onKeyUp="countChars('{$key}','{CHAR}',1000);""></textarea>
<span id="counter_{$key}">1000</span>
BLA;
}

If the keys in your array aren't usable as above, then add a counter variable that you increment on each iteration instead, and use that as the key. You'll notice a difference in the countChars function call, where we just pass the key, or the unique part of textarea_ and counter_ to your Javascript function.

Then, the Javascript function is modified to match:

function countChars(itemId, text, characters) {
    var entranceObj = document.getElementById('textarea_'+itemId);
    var exitObj = document.getElementById('counter_'+itemId);
    // ...
}

We generate the actual IDs for both the textarea and the counter on the basis of the unique bit. Now, you could also pass the full IDs in two arguments, but it's basically just redundant bulk. It's cleaner to keep function signatures minimal and regenerate patterns like this.

Markus AO
  • 4,771
  • 2
  • 18
  • 29
  • 1
    Markus and GrafiCode. I managed to solve it now with both your help. Thanks alot! – leo May 07 '22 at 11:58
  • @leo great. P.S. Passing `{CHAR}` as the `text` function argument isn't really needed when your `replace` is hard-wired to only replace `{CHAR}` anyway. You could just drop the `text` argument and `replace` altogether and simply do `var text = '' + length + '';` by the looks of it. – Markus AO May 07 '22 at 12:08
  • 1
    @leo You can skip setting `onKeyUp` in PHP entirely and add the eventhandlers in JS by `Array.from(document.getElementsByTagName('textarea')).forEach(ta=>ta.addEventListener('keyup', countChars))`. Then you can save the querySelector entirely and [get](/q/1803195) the textarea via `var entranceObj = this` – cachius May 07 '22 at 12:32