1

I'm trying to build a menu, highlight the current tab/page the user is on, add a color class, and use JavaScript to update the active link. This is my template:

<div class="w3-bar w3-black">
  <button
    class="w3-bar-item w3-button tablink w3-red"
    onclick="openCity(event,'London')"
  >
    London
  </button>
  <button
    class="w3-bar-item w3-button tablink"
    onclick="openCity(event,'Paris')"
  >
    Paris
  </button>
  <button
    class="w3-bar-item w3-button tablink"
    onclick="openCity(event,'Tokyo')"
  >
    Tokyo
  </button>
</div>

<div id="London" class="w3-container w3-border city">
  <h2>London</h2>
  <p>London is the capital city of England.</p>
</div>

<div id="Paris" class="w3-container w3-border city" style="display:none">
  <h2>Paris</h2>
  <p>Paris is the capital of France.</p>
</div>

<div id="Tokyo" class="w3-container w3-border city" style="display:none">
  <h2>Tokyo</h2>
  <p>Tokyo is the capital of Japan.</p>
</div>

And I have this javascript code in 'methods':

methods: {
    openCity: function(evt, cityName) {
      var i, x, tablinks;
      x = document.getElementsByClassName("city");
      for (i = 0; i < x.length; i++) {
        x[i].style.display = "none";
      }
      tablinks = document.getElementsByClassName("tablink");
      for (i = 0; i < x.length; i++) {
        tablinks[i].className = tablinks[i].className.replace(" w3-red", "");
      }
      document.getElementById(cityName).style.display = "block";
      evt.currentTarget.className += " w3-red";
    }
  }

But I got this error in console: 'TypeError: Cannot read property 'className' of undefined' and the button it doesn't highlight it. Hope you can help me, thanks!

1
  • What className is undefined? tablinks[i].classNam or evt.currentTarget.className? Commented Jul 19, 2020 at 14:25

1 Answer 1

2

You are passing event instead of $event, I think this is why it's not defined. Also you have a lot of unnecessary code. I cleaned it up, try now:

HTML

<div class="w3-bar w3-black">
  <button
    v-for="city in cities"
    class="w3-bar-item w3-button tablink"
    @click="openCity($event, city)"
    :class="{ 
      'w3-red': city.name === selectedCity,
      'w3-black': city.name !== selectedCity 
    }"
  >
    {{city.name}}
  </button>
</div>

<div 
  v-for="city in cities" 
  :id="city.name" 
  class="w3-container w3-border city"
  :class="{ 
    'visible': city.name === selectedCity,
    'hidden': city.name !== selectedCity 
  }"
 >
  <h2>{{city.name}}</h2>
  <p>{{city.description}}</p>
</div>

script

data () {
  return {
    selectedCity: 'London',
    cities: [
      { 
        name: 'London', 
        description: 'London is the capital city of England'
      },
      { 
        name: 'Paris', 
        description: 'Paris is the capital of France',
      },
      { 
        name: 'Tokyo', 
        description: 'Tokyo is the capital of Japan',
      }
    ] 
  }
},
methods: {
  openCity (event, city) {
    this.selectedCity = city.name
  }
}

styles

.hidden {
  display: none
}

.visible {
  display: block
}

Method 2

If you don't want to use CSS classes to hide the content, you can just use v-show and only the selected city will be shown city.name === selectedCity:

<div 
  v-for="city in cities" 
  v-show="city.name === selectedCity"
  :id="city.name" 
  class="w3-container w3-border city"
 >
  <h2>{{city.name}}</h2>
  <p>{{city.description}}</p>
</div>
Sign up to request clarification or add additional context in comments.

1 Comment

@NuzzeSicK glad I could help :). I updated the code again, take a look, I made it more flexible. This way it will be much easier to work with when you have more data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.