-2

I am using the W3.CSS animated drop-down (https://www.w3schools.com/w3css/w3css_dropdowns.asp).

But I cannot figure out how can I populate the menu items dynamically according to a list of item names.

I guess some Javascript should be involved here, so I try in this forum

 <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<div class="w3-dropdown-click">
   <button onclick="showMenu()" class="w3-button">Team1</button>
   <div id="Demo" class="w3-dropdown-content w3-bar-block w3-animate-zoom">
       <a href="#" class="w3-bar-item w3-button">Link 1</a>
       <a href="#" class="w3-bar-item w3-button">Link 2</a>
       <a href="#" class="w3-bar-item w3-button">Link 3</a>
   </div>
</div>

<script>


async function getTeams() {
    try{
        (async () => {
            const response = await fetch('http://localhost:8088/teams')
            var teamsArrObj = await response.json()
            console.log(teamsArrObj);
            return teamsArrObj;
        })()
    }catch{
        console.log("error");
    }
}


function showMenu() {
  var x = document.getElementById("Demo");
  if (x.className.indexOf("w3-show") == -1) {
    x.className += " w3-show";
  } else { 
    x.className = x.className.replace(" w3-show", "");
  }
}
</script>

Thanks!

dushkin
  • 1,939
  • 3
  • 37
  • 82
  • So you're trying to create the elements in JS using an array of text am i right? –  Oct 27 '20 at 17:03
  • Please show what JavaScript you have tried and we can help you fix it. – Mark Schultheiss Oct 27 '20 at 17:05
  • Maybe that gives some idea how to: https://stackoverflow.com/questions/6334628/jquery-append-to-bottom-of-list – lohe Oct 27 '20 at 17:11
  • You miss to copy the js from : https://www.w3schools.com/w3css/tryit.asp?filename=tryw3css_dropdown_click – MaxiGui Oct 27 '20 at 17:13
  • The W3 Schools example uses CSS and the `:hover` pseudo-class. You are trying to do it with JavaScript and the `click` event. Two completely different approaches. – Scott Marcus Oct 27 '20 at 17:13
  • Also, stay as far away from W3 Schools as you can. The site is well-known to have incomplete, out of date, or flat out wrong information. Even the example you are referencing in your question is one where they show an outdated approach. Use [The Mozilla Developer Network](https://developer.mozilla.org/en-US/) (MDN) instead. – Scott Marcus Oct 27 '20 at 17:16
  • @ScottMarcus I got most of my basic HTML skills from W3schools –  Oct 27 '20 at 17:16
  • @expressjs123 No offense, but you probably learned many things that are incorrect or outdated, like using inline HTML event attributes or self-terminating syntax. It's very difficult for people to know what they don't know. This is not just my opinion, it's well-known and documented. – Scott Marcus Oct 27 '20 at 17:19
  • @ScottMarcus Maybe, as my first few websites used bad practices and didn't look very good. But my foundations came from there, like the main syntax, how to put CSS, the semantics etc. however it wasn't until I took a proper course that I began using modern techniques –  Oct 27 '20 at 17:21
  • @ScottMarcus No. Look at the Animated Dropdown version at the bottom of the page. Regarding your recommendation - I am really doing now my first full stack project and currently I am searching for relatively simple implementations. But, thanks :) – dushkin Oct 27 '20 at 17:28
  • @dushkin Please don't confuse "simple" for "correct" In fact, the example at W3 Schools is more involved than it needs to be and uses older ways of doing what is much simpler with modern code. Trust me, I've been doing this stuff and teaching it since it was invented. Learn from a trusted source so you don't develop bad habits. – Scott Marcus Oct 27 '20 at 18:53
  • For example, in that code that you reference, they have forgotten to place the `title`, `meta` and `link` elements at the top into a `head` element, which is invalid HTML. They start out with an `h2`, which is semantically incorrect and will be problematic for those who use assistive technologies to access web content. They use inline HTML event attributes, which should not be used and are centering the JavaScript logic around the `className` string, which requires the use of `indexOf` and `.replace()`, instead of simply using the `.classList` API. In short, that code is bad. – Scott Marcus Oct 27 '20 at 18:59
  • @ScottMarcus Thank you Scott for your insights. I'll keep them in mind :) – dushkin Oct 27 '20 at 20:45

2 Answers2

1

Assuming that you're using a regular js array of text, you can loop over that array and insertAdjacentHTML into the dropdown.

for (let text of /*insert array name here*/) {
document.getElementById('Demo').insertAdjacentHTML('beforeend', `<a href="#" class="w3-bar-item w3-button">${text}</a>`

Here we use the modern for...of loop, and do insertAdjacentHTML. Check the MDN docs if you are not familiar with the function. We also use the ES6 template strings to insert.

  • It is an objects array, but I will extract the menu items text from each object – dushkin Oct 27 '20 at 17:23
  • Yeah you can just apply whatever structure you have to what I posted –  Oct 27 '20 at 17:26
  • expressjs123, Actually I get my menu items texts from an array which I get like this: async function getTeams() { try{ (async () => { const response = await fetch('http://localhost:8088/teams') var teamsArrObj = await response.json() .... I need to extract the menu item names from the teamsArrObj items. However, this object is not exactly an array but a Promise (am I correct here?). How can I handle this? – dushkin Oct 27 '20 at 21:22
-1

Because W3 Schools has so much wrong in their demo that you've linked to, I've recreated their example (the right way) and shown how the CSS would be done (instead of relying on their pre-made CSS that you don't get to see).

You'll note that the actual hiding/showing of the menu is accomplished with a single line of JavaScript instead of all that outdated string related stuff that W3 Schools uses.

And, you'll see how you can dynamically load the menu items from an array of object data.

<!DOCTYPE html>
<html>
<head>
  <title>W3.CSS</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    button {
      background-color:black; 
      color:white;
      padding:5px;
      border:none;
      font-size:1.1em; /* 10% bigger than normal */
    }
  
     #Demo {
       position:relative;
       box-shadow:0 0 20px #808080;
       padding:6px;
       margin-top:3px;
       height:auto;
       width:75px;
       transform-origin: center;  /* Make effect work from center outward */
       transition:all .5s; /* Make changes to all CSS happen over 1 second */
     }
     
     /* The style of the menu when it's hidden */
     #Demo.hidden { 
       transform:scale(0,0); /* Scale it to 0 by 0 pixels */
     }
     
     .menuItem { 
       display:block; /* Each item on its own line */
       text-decoration:none; /* no underline on the links */
       padding:3px;
       font-family:Arial;
     }
     
     .menuItem:hover {
       background-color:#e0e0e0; 
     }
  </style>
</head>
<body>

<div>
  <h1>Animated Dropdown</h1>

  <div class="w3-dropdown-click">
    <button>Click me</button>
    <div id="Demo" class="hidden"></div>
  </div>
</div>

<script>
  let items = [
    { text: "Link 1", path: "https://example.com"},
    { text: "Link 2", path: "https://hbo.com"},
    { text: "Link 3", path: "https://cbs.com"},    
  ];

  const demo = document.getElementById("Demo");
  
  // Loop over the items array
  items.forEach(function(item){
    // Create a new anchor element and configure it:
    let link = document.createElement("a");
    link.classList.add("menuItem");
    link.href = item.path;
    link.textContent = item.text;
    
    // Append the new link to the menu
    demo.appendChild(link);
  });
  
  document.querySelector("button").addEventListener("click", function(){
      demo.classList.toggle("hidden"); // Toggle the display of the menu
  });
</script>

</body>
</html>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • It wasn't me who down voted your answer. I'll be happy if he\she could explain. Thanks – dushkin Oct 27 '20 at 20:46
  • @dushkin If my answer answers your question (I've shown and documented how to create dynamic links from a list), please up vote it and mark it as "the" answer by clicking the check mark at the top left of the answer. – Scott Marcus Oct 27 '20 at 20:47
  • Scott, I get my menu items texts from an array which I get like this: async function getTeams() { try{ (async () => { const response = await fetch('http://localhost:8088/teams') var teamsArrObj = await response.json() .... I need to extract the menu item names from the teamsArrObj items. However, this object is not exactly an array but a Promise (am I correct here?). How can I handle this? – dushkin Oct 27 '20 at 21:20
  • Can you edit your question to show what the array looks like that you get back? All that needs to happen is that when that response comes back (and yes it is in the Promise), you would loop over it (similarly to what I'm doing in my answer) and create the menu items. – Scott Marcus Oct 27 '20 at 21:39
  • I added the getTeams() function. I expect it to return me an array of team objects. Each object is of the mapping of a response json (example): {id: 1, name: "mta", country: "USA"}... and I need the names to be the menu items – dushkin Oct 27 '20 at 21:43
  • @dushkin So, where (in my code), I'm doing `items.forEach()`, you'd replace `items` with the reference to your array. And inside that block, where I'm saying `link.textContent = item.text`, you'd say `link.textContent = item.name;` (because your array contains objects with a `name` property. I don't know what you'll use for the `item.href` as I assumed that you want the items on the menu to be links that would point somewhere. – Scott Marcus Oct 27 '20 at 21:51
  • The entire `.forEach()` block of code must be placed in your Promise callback, so it only runs once you've received the array. – Scott Marcus Oct 27 '20 at 21:52
  • Bingo! Thank you my man for your precious time! I am so grateful! I accepted the answer, but if you wish you can update it to be complete as I needed. – dushkin Oct 27 '20 at 22:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223765/discussion-between-dushkin-and-scott-marcus). – dushkin Oct 28 '20 at 15:20