execute a function only if condition is satisfied inside for loop

699 views Asked by At

I am new to js and I am trying to loop through elements by class name and make a change to the element's textcontent using javascript. The following is what I have so far, but this does not work.

<script type="text/javascript">
function dformat(i) {
    var hasDate = document.getElementsByClassName("dformat")[i].textContent.trim().includes("/");
    if(hasDate === false) {
       window.setTimeout(dformat, 100); /* this checks the flag every 100 milliseconds*/
    } else {
       dateString = document.getElementsByClassName("dformat")[i].textContent.trim();
       const options = { year: 'numeric', month: 'short', day: 'numeric' };
       let dateArr = dateString.split("/");
       var sMonth = dateArr[0];
       var sDay = dateArr[1];
       var sYear = dateArr[2];
       let newDateString = sYear + "/" + sMonth + "/" + sDay
       let newDate = new Date(newDateString);
       document.getElementsByClassName("dformat")[i].textContent=newDate.toLocaleDateString('en-us', options);
    }
}

var ditems = document.getElementsByClassName("dformat");
for (var i = 0; i < ditems.length; i++) {
  dformat(i);   
}
</script>

The following is an example of one of the elements

<span class="dformat">26/06/1992</span>

The expected output would be to have changed text on each of the elements with class dformat

Update: I tried the same function with getelementbyid on a single element (i.e without a for loop) and got the expected result. I have trouble doing the same on a set of elements by classname instead of a single element by id.

3

There are 3 answers

0
TechnoSam On BEST ANSWER

There's nothing wrong with your for loop, the problem is with your Date objection construction. Dates cannot be created with the YYYY/MM/DD format. (See warning section here) What you instead need to do is pass the year, month, and day as parameters to the constructor.

let newDate = new Date(sYear, sMonth, sDay);

Some other notes...

You don't need to use document.getElementsByClassName to find the elements each time. You can simply pass the element directly to the function.

function dformat(e) {
  dateString = e.textContent.trim();
  if (!dateString.includes('/')) {
    window.setTimeout(dformat, 100, e);
    return;
  }
  const options = { year: 'numeric', month: 'short', day: 'numeric' };
  let dateArr = dateString.split("/");
  var sMonth = dateArr[0];
  var sDay = dateArr[1];
  var sYear = dateArr[2];
  let newDate = new Date(sYear, sMonth, sDay);
  e.textContent=newDate.toLocaleDateString('en-us', options);
}

var ditems = document.getElementsByClassName("dformat");
for (var i = 0; i < ditems.length; i++) {
  dformat(ditems[i]);   
}

Here's a code snippet showing this in action.

function dformat(e) {
  dateString = e.textContent.trim();
  if (!dateString.includes('/')) {
    window.setTimeout(dformat, 100, e);
    return;
  }
  const options = { year: 'numeric', month: 'short', day: 'numeric' };
  let dateArr = dateString.split("/");
  var sMonth = dateArr[0];
  var sDay = dateArr[1];
  var sYear = dateArr[2];
  let newDate = new Date(sYear, sMonth, sDay);
  e.textContent=newDate.toLocaleDateString('en-us', options);
}

var ditems = document.getElementsByClassName("dformat");
for (var i = 0; i < ditems.length; i++) {
  dformat(ditems[i]);   
}
<span class="dformat">26/06/1992</span>
<br>
<span class="dformat">27/06/1992</span>
<br>
<span class="dformat">28/06/1992</span>
<br>
<span class="dformat">29/06/1992</span>

Secondly, if you use setTimeout, you will need to pass the element to the function. As you have it, the function will be called with no arguments, so it would break if it ever found something without a /. You can see how I did it above to fix that.

I'm a little suspicious of using setTimeout in this way. This only allows the spans to be formatted once, if you really want continuous monitoring then you you will need to constantly setTimeout outside the function definition in the main script. Or if you just need to wait for the document to be ready, you should place your scripts after your HTML content and that will not be a problem. (See here). I won't speculate further since that isn't the purpose of this question, but I wanted to let you know that something seems wrong there.

0
Athanasios Kataras On

My guess is that some value gives you an exception.

Try this:

var ditems = document.getElementsByClassName("dformat");
for (var i = 0; i < ditems.length; i++) {
  try {
    dformat(i);   
  }
  catch (error) {
    console.error(error);
  }
}

If it works, log the i in the exception to see the failing value.

0
UnsignedByte On

setTimeout() will forget what index you are running dformat on. You should use setTimeout(dformat, 100, i) to pass on the parameter to the next call, so you can have multiple independent waits running at once.