TheCrazyTech
TheCrazyTech

Reputation: 51

Click and show?

I am working with this:

<html>
<ol onclick="myevent(event);">
  <li title="a">Test 1</p>
    <li title="b">Test 2</p>
</ol>
<div id="a" style="display:none;">Text to show</div>
<div id="b" style="display:none;">Other text to show</div>

<script>
  function myevent(event) {

    var x, i, clk, res;
    x = document.getElementsByTagName("DIV");
    for (i = 0; i < x.length; i++) {
      x[i].style.display = "none";
    }
    clk = event.target.title;
    res = document.getElementById(clk);

    res.style.display = "block";

  }
</script>

</html>

Essentially click one line item, hide all blocks, and then show the named block. This should be simple but I have been researching for hours and getting nowhere.

Thanks in advance! - Joe

Upvotes: 1

Views: 91

Answers (2)

zer00ne
zer00ne

Reputation: 43990

Event Handlers

There's three ways to handle an event (in this case the click event on <ol>):

  • Event Attribute (not recommended)

    <ol onclick="eventHandler(); return false">...</ol>
    
  • Event Property

    document.querySelector('ol').onclick = eventHandler;
    
  • Event Listener (recommended)

    document.querySelector('ol').addEventListener('click', eventHandler);
    

For details refer to Introduction to Events and DOM Onevent Handlers


Event Delegation

The following demo uses a programming paradigm called Event Delegation. The advantages over the code provided in OP (Original Post) are:

  • Only one tag needs to be registered as the event listener (common ancestor tag of all targeted tags - ex. <ol> is an ancestor tag to all <li>).

  • There's no need to loop thru each targeted tag and register each one to an event (ex. <li> do not have to be in a for loop).

  • There can be an unlimited number of targeted tags and knowing how many is not required. (ex. there can be a single <li> to theoretically thousands of <li>).

  • The targeted tags can be added dynamically anytime -- during or after page load. If done any other way, any dynamically added tags would not work without reloading the page and somehow keeping them.

Refer to Event Delegation for details.


References

In the following demo these methods and properties were used:

DOM

Event


Demo

Details are commented in demo

/* EVENT DELEGATION */
// Register Ancestor Tag to Event
/*
Register the click event to a common ancestor tag of all 
tags you want to be clickable.
So in this instance the clickable tags are all <li>
Ancestor tags could be:
  window
  document
  <body>
  <main>
  <ol>
Usually the closest tag is the best choice which is <ol>
*/
// ------ Breakdown ------
/* 
  document.querySelector('ol') 
  -- find <ol>

  .addEventListener('click'... 
  -- register click event to <ol>

  ..., eventHandler); 
  -- run function eventHandler() when <ol> is clicked
*/
document.querySelector('ol').addEventListener('click', eventHandler);

// Event Object
/* 
Pass event object which will have properties and methods that will allow us to:
  1. find what tag is listening for click event
    - event.currentTarget
    - in this demo it is <ol>
  2. find what tag the user actually clicked
    - event.target
    - in this demo only <li> will react to being clicked
  3. stop the click event from "bubbling" up the event chain
    - event.stopPropagation();
    - this method is called at the end of eventHandler() so
      that the click event doesn't trigger anything else
*/
function eventHandler(event) {
  // Reference all tags concerned
  // See Event Object #1
  const listener = event.currentTarget;
  // See Event Object #2
  const clicked = event.target;
  // Find <output>
  const display = document.querySelector('output');

  // ------ Breakdown ------
  /*
  if <ol> isn't the tag that the user clicked...
  ... and if the clicked tag is a <li>...
  ... get the text inside that <li>...
  ... and place it in <output> 
  (it gets overwritten on each click so there's no need for multiple tags)
  */
  if (listener !== clicked) {
    if (clicked.tagName === 'LI') {
      let data = clicked.textContent;
      display.textContent = data;
    }
  }
  /*  
  Regardless of whether any <li> were clicked stop the click event
  See Event Object #3
  */
  event.stopPropagation();
}
main {
  font: 700 1rem/1.5 Tahoma
}

li:hover {
  cursor: pointer
}
<main>
  <ol>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
    <li>F</li>
  </ol>
  Item: <output></output>
</main>

Upvotes: 0

Mamun
Mamun

Reputation: 68923

You have some typos in your code.

Firstly, you are wrongly closing li element with </p>

Secondly, getElementsBytagname should be getElementsByTagName and getelementbyid should be getElementById:

function myevent(event){

  var x, i, clk, res;
  x = document.getElementsByTagName("DIV");
  for (i = 0; i < x.length; i++) {
    x[i].style.display = "none";
  }
  clk = event.target.title;
  res = document.getElementById(clk);

  res.style.display="block";

}
<ol onclick="myevent(event);">
  <li title="a">Test 1</li>
  <li title="b">Test 2</li>
</ol>
<div id="a" style="display:none;">Text to show</div>
<div id="b" style="display:none;">Other text to show</div>

You can also try using querySelectorAll() and forEach() that does not require the loop variable i:

function myevent(e){

  var x, clk, res;
  x = document.querySelectorAll("DIV");
  x.forEach(div => div.style.display = "none");  
  clk = e.target.title;
  res = document.getElementById(clk);

  res.style.display="block";

}
<ol onclick="myevent(event);">
  <li title="a">Test 1</li>
  <li title="b">Test 2</li>
</ol>
<div id="a" style="display:none;">Text to show</div>
<div id="b" style="display:none;">Other text to show</div>

Upvotes: 1

Related Questions