0

I'm trying to display parts of the date on a page using the ID, I have to use the ID multiple times on a page, and I've been told that I need to change that to class, and I'm unsure how to do that.

I've created this jsfiddle.

The HTML is as follows, but I need to use some of those ID's multiple time, and using a second instance of it doesn't show/work.

<p>The date is <a id="date"></a></p>
<p>The current month and year is <a id="month-year"></a></p>
<p>The current day and month is <a id="day-month"></a></p>
<p>The current year is <a id="year"></a></p>
<p>The current month is <a id="month"></a></p>
<p>Today is the <a id="day"></a> of <a id="month"></a></p> 

In the last example <a id="month"> will not show.

the JS I'm using is as follows.

var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var n = new Date();
var y = n.getFullYear();
var m = n.getMonth();
var d = n.getDate();
var dateObject = document.getElementById("date");
if (dateObject) dateObject.innerHTML = d + " " + months[m] + " " + y;
var month_year = document.getElementById("month-year"); 
if (month_year) month_year.innerHTML = months[m] + " " + y;
var day_month = document.getElementById("day-month");
if (day_month) day_month.innerHTML = d + " " + months[m];
var year = document.getElementById("year");
if (year) year.innerHTML = y;
var month = document.getElementById("month");
if (month) month.innerHTML = months[m];
var day = document.getElementById("day");
if (day) day.innerHTML = d;

How can I change the above code so I can use the ID/class multiple times on a page?

user2240778
  • 309
  • 5
  • 16
  • How are you using `id` multiple times? – gaganshera May 13 '20 at 16:02
  • Change `id` to `class` and then use `document.querySelector(".ClassNameHere")` to find the first occurrence of an element with that class or `document.querySelectorAll(".ClassNameHere")` to get a collection of all elements with that class name. – Scott Marcus May 13 '20 at 16:03
  • For example if you visit the jsfiddle and put in twice, it will only show one instance of it. – user2240778 May 13 '20 at 16:04
  • And, don't use `.innerrHTML` when the string you are working with doesn't contain any HTML as `.innerHTML` has performance and security implications. Use `.textContent` instead. – Scott Marcus May 13 '20 at 16:05
  • I'm not very well versed with coding. This is what I've changed it to var dateObject = document.querySelectorAll("date"); if (dateObject) dateObject.textContent = d + " " + months[m] + " " + y; and it doesn't work – user2240778 May 13 '20 at 16:08
  • @ScottMarcus—while it is more semantic to use *textContent* rather than *innerHTML* in this case, your reasons are spurious. There are no more security implications for innerHTML than with setting any other DOM property (pretty much zero). It's a core property used in jQuery and other highly regarded DOM libraries. For simple text, the performance difference is insignificant. – RobG May 13 '20 at 22:24

2 Answers2

2

I think this is what you are after. See the comments for details.

var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var n = new Date();
var y = n.getFullYear();
var m = n.getMonth();
var d = n.getDate();

// Get all the containers into a collection
var dateHolders = document.querySelectorAll(".dateHolder");

// Loop over each container in the colletion
dateHolders.forEach(function(holder){

  // Search within the container for the first element that 
  // matches the selector passed to querySelector
  var dateObject = holder.querySelector(".date");
  var month_year = holder.querySelector(".month-year");
  var day_month = holder.querySelector(".day-month");
  var day_month = holder.querySelector(".day-month");
  var year = holder.querySelector(".year");
  var month = holder.querySelector(".month");
  var day = holder.querySelector(".day");

  // Wrap your branching statements in {}
  if (dateObject) { dateObject.textContent = d + " " + months[m] + " " + y; }
  if (month_year) { month_year.textContent = months[m] + " " + y; }
  if (day_month) { day_month.textContent = d + " " + months[m]; }
  if (year) { year.textContent = y; }
  if (month) { month.textContent = months[m]; }
  if (day) { day.textContent = d; }
  
});
<!-- 
   <a> elements are for navigation, not simple display of text.
   Use more generic tags to show general inline content. Also, wrap the whole
   set of data about the date in a container to make it easier to
   reproduce it.
-->
<div class="dateHolder">
  <span class="date"></span>
  <span class="month-year"></span>
  <span class="day-month"></span>
  <span class="year"></span>
  <span class="month"></span>
  <span class="day"></span>
</div>

<div class="dateHolder">
  <span class="date"></span>
  <span class="month-year"></span>
  <span class="day-month"></span>
  <span class="year"></span>
  <span class="month"></span>
  <span class="day"></span>
</div>

<div class="dateHolder">
  <span class="date"></span>
  <span class="month-year"></span>
  <span class="day-month"></span>
  <span class="year"></span>
  <span class="month"></span>
  <span class="day"></span>
</div>

<div class="dateHolder">
  <span class="date"></span>
  <span class="month-year"></span>
  <span class="day-month"></span>
  <span class="year"></span>
  <span class="month"></span>
  <span class="day"></span>
</div>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
0

Simply exchange id with class and iterate over the elements. The below code expects that each of the elements will be available in the DOM the same number of times, otherwise you will need to adapt the code.

HTML:

<a class="date"></a>
<a class="month-year"></a>
<a class="day-month"></a>
<a class="year"></a>
<a class="month"></a>
<a class="day"></a>
<br>

<a class="date"></a>
<a class="month-year"></a>
<a class="day-month"></a>
<a class="year"></a>
<a class="month"></a>
<a class="day"></a>
<br>

JS:

let numElements = document.getElementsByClassName("date").length;

for (let i = 0; i < numElements; i++) {
  ...

  var dateObject = document.getElementsByClassName("date")[i];
  if (dateObject) dateObject.textContent = d + " " + months[m] + " " + y;
  ...
}

A fiddle can be found here.

SaschaM78
  • 4,376
  • 4
  • 33
  • 42
  • 1
    **`document.getElementsByClassName("date")[i]` is one of the worst things you can do.** [It's 2020. Let's never use `getElementsByClassName()` again.](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474) – Scott Marcus May 13 '20 at 16:21
  • 1
    @ScottMarcus thanks for pointing me to this, I'll keep this in mind in the future. – SaschaM78 May 13 '20 at 17:22
  • There's no real issue with *getElementsByClassName* except that you should call it once then iterate over the NodeList, rather than calling it on each loop. Also, being live, it has some quirks that are useful or not. As for being slower than *querySelectorAll*, it isn't. – RobG May 13 '20 at 22:14
  • @ScottMarcus—I disagree with your comment. The performance test at your [linked answer](https://stackoverflow.com/a/54952474/257182) is flawed, see my comment at that answer. – RobG May 13 '20 at 22:34
  • @RobG See my detailed response at that other answer, but the test is not flawed. Both scenarios have the exact same code within the loop body. The only thing that differs is the type of node list used and the live list is roughly 72% slower. This clearly shows that live lists are slower than static ones. – Scott Marcus May 14 '20 at 13:00
  • @ScottMarcus I also ran the performance test yesterday on FF77 on Windows 10 and the static node list was 77% slower than the live list. – SaschaM78 May 14 '20 at 13:04