0

I've been developing a snippet of code for a while now mostly using Pure JS I'm not to well versed on JS but I can walk my way around it within reason. I'm trying to target an element of HTML that has been placed inside a JS created div.

The idea is to change the color of a character counter when it gets to 50 then finally 0. I have tried to implement the following snippet myself but I'm having difficulties trying to get it to work correctly.

After some digging around the net I stumbled upon a question located here, Stack Overflow Question. Mentioning the need to dive deeper in sourcing the element thats being targeted I.e. var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];. However I feel it doesn't really apply to me as I'm not giving my created div an ID or using classes.

Here's what I tried to implement,

 // create wrapper element
  this.wrapper = document.createElement("div");
  this.wrapper.innerHTML = 'Chars left: <span id="int">' + (this.MAX - input.value.length), '</span>';

// The <span></span> element is the one I am trying to adjust.

// check counter value
var tail = document.getElementById("int");

if (this.MAX - this.INPUT.value.length <= 50) {
    tail.style.color = "#ffa";
} else if (this.MAX - this.INPUT.value.length <= 0) {
    tail.style.color = "#f00";
}

You can find the full code snippet I've been creating using JSFiddle. Can anyone help me identify what I am missing here, or enlighten me as to if I'm approaching this wrong?

Community
  • 1
  • 1
Lewis
  • 1,945
  • 5
  • 26
  • 52
  • `this` refers to what scope? – Dropout Aug 15 '16 at 13:55
  • `this` refers to `window` object. `this.INPUT` (which is `window.INPUT`) doesn't actually exist – Adam Azad Aug 15 '16 at 14:01
  • 1
    In addition to this.Input being out of scope, multiple elements in a document cannot have the same ID, which in this case, your spans all have the same ID which is not allowed. Secondly, you'll certainly need to attach event listeners and only trigger the color-updating code when there is an update in the text boxes. I'll try to come up with a JSFiddle for you. – Ted Aug 15 '16 at 14:02
  • @Ted It appears I wasn't thinking correctly when I added ID's. I did think about using `document.getElementsByTagName("span");`. But didn't want any conflict with other spans in the html document. It would make more sense to use classes here instead? – Lewis Aug 15 '16 at 14:10
  • 1
    You'd ultimately run into the same issue if you use classes, as it'd be very annoying to try to pin down which span you want, since you'd get back an array of spans using `document.getElementsByClassName`. I'd recommend still going the ID route, and set unique IDs by passing in a unique number (like the index in your for-loop), and then setting the id as `'id ' + this.idNum`. That way, you get simply get the tail variable by `document.getElementById('id ' + this.idNum)` Let me know if you need further clarification, that was kinda confusing haha – Ted Aug 15 '16 at 14:14
  • @Ted, I think my brain may have just exploded... xD Is this even possible considering the way I am building the spans? – Lewis Aug 15 '16 at 14:20
  • 1
    Indeed! So essentially you'd do: `'Chars left: ' + (this.MAX - input.value.length), ''` However this is really messy. I'd highly recommend moving towards a different structure, where you create a new span, save the span to a variable, and append it as a child to your wrapper. That way you can save the reference to the span and never have to worry about finding it again! – Ted Aug 15 '16 at 14:41
  • Sounds simple enough when you put it like that, lol. One additional question, that was not aware of untill you mentioned using the index of my for loop. When I convert `i.toString();` I get 7 when I belive there should only be four? could you explain why this might be happening? Check updated fiddle. – Lewis Aug 15 '16 at 14:45
  • I believe that is happening because the parent node of the text area is the whole div, which is is including the text boxes and the divs that hold the char counts. Not entirely sure why its 7 though. Tbh not very good at debugging through JSFiddle haha, i need my chrome developer tools – Ted Aug 15 '16 at 15:11
  • lol, I understand that an index counts from 0 onwards but how it got seven is beyond me. Fiddle debugging is a pain. but it helps if your developing just java and not any html or web related assets. – Lewis Aug 15 '16 at 15:16
  • Oh ok i see why it's 7. So the `i` is referring to the last value of the for-loop above it. The very LAST time that loop gets run, and hence the very LAST time that the `div` gets updated, is when you're searching for that final textarea, which is element number 7 in `ipar`'s children. So that's why it's displaying 7. – Ted Aug 15 '16 at 15:38

2 Answers2

1

Looks like you need to listen for when a character is entered into the input. Those .value.length properties aren't updated live, so you'll need to check every time the user presses a key.

// create wrapper element
this.wrapper = document.createElement("div");
this.wrapper.innerHTML = 'Chars left: <span id="int">' + (this.MAX - input.value.length), '</span>';

// check counter value
var tail = document.getElementById("int");

// Inside the event handler function, the "this" keyword changes meaning to mean the element on which the event listener is attached. Redefining the variable here is one way to get max inside the handler.
var max = this.MAX;

this.INPUT.addEventListener('keyup', function () {
    if (max - this.value.length <= 50) {
        tail.style.color = "#ffa";
    } else if (max - this.value.length <= 0) {
        tail.style.color = "#f00";
    }
}

You might also want to check the logic of else if (max - this.value.length <= 0) - the length will never be less then zero :) Also, what do you want to happen when it goes above 50?

beingmrkenny
  • 192
  • 1
  • 10
  • The color of the text above 50 should remain, 80% black, but I haven't told my code to revert back to that. Thank you for pointing that out... :) – Lewis Aug 15 '16 at 14:06
  • Would the var tail set correctly though? He's creating multiple spans with the same ID, which is not allowed. – Ted Aug 15 '16 at 14:10
  • @beingmrkenny I was under the impression that `<=` was the correct scinario in this case? As it wouldn't ever go below '0'. But what if, for some reason it did? – Lewis Aug 15 '16 at 14:12
  • 1
    It doesn't hurt to have it there I suppose, but I can't see how it would ever go below zero. As a heads up, if you do change this to check if it equals zero, `=== 0` is the syntax you'll need, since the `===` operator also checks type. `== 0` can match null, false and an empty string, for example. – beingmrkenny Aug 15 '16 at 14:15
  • @beingmrkenny to add some context sometimes these textareas are pulling data from a server, and the content can be edited back end. Sadly I've already seen some occurances of this. I'm only allowing it to preserve data. – Lewis Aug 15 '16 at 14:17
1

Stylize in this:

TextAreaRanger.prototype["update"] = function() {.....}
kollein
  • 328
  • 3
  • 10