3

I am learning Vuejs and I am constantly finding simple things like removing a class to be a pain. Please tell me how I can allow the .active class to be added or removed based on clicks between the 3 links.

In the example below the adding is working fine but it adds .active to all the links, and does not remove when clicked on again.

<div id="app">
  <h2>App</h2>
  <ul>
    <li><a href="#" class="link" :class="{ active: isActive }" @click="activeLink">Link text</a></li>
    <li><a href="#" class="link" :class="{ active: isActive }" @click="activeLink">Link text</a></li>
    <li><a href="#" class="link" :class="{ active: isActive }" @click="activeLink">Link text</a></li>
  </ul>
</div>

JS

var app = new Vue({
  el: '#app',
  data: {
    isActive: false
},
methods: {
  activeLink() {
    // the line below did not work
    // document.getElementsByClassName("active").isActive = false,
    this.isActive = true
  }
 }
})

JSfiddle is here, https://jsfiddle.net/s9r4q0gc/

0

4 Answers 4

7

You need to catch the event handler in the method and using that you can refer to the callee i.e. anchor object in this case.

See the fiddle : https://jsfiddle.net/s9r4q0gc/2/

activeLink(event) {
    if(event.target.className == "noclass")
    {
        event.target.className = "link active";
    }
    else
    {
        event.target.className = "noclass";
    }
  }

UPDATED:

May be try this fiddle and see if it is hitting the bulls eye : https://jsfiddle.net/s9r4q0gc/4/

  var app = new Vue({
    el: '#app',
    data: {
      isActive: false
    },
    methods: {
      activeLink(event) {
        var checkboxes = document.getElementsByClassName ("noclass");

        for (var i=0; i<checkboxes.length; i++) {
           checkboxes[i].className = "link active";
           //checkboxes[i].className = "link";
        }
            event.target.className = "noclass";
      }
    }
  })
Sign up to request clarification or add additional context in comments.

5 Comments

Hi looking at your fiddle, that does not remove .noclass when clicking on another link.
Ah you want to remove that class on click on any other anchor. Couldn't understand.
This one will reset the class on clicking again on the same element. Just a toggle effect. Try and see.
Yeah I see, is there any way to make it toggle across all three links? I've tried with your example but can't get it to work.
Check the updated fiddle. It is removing the "noclass" from all the links, assign the "link active" class to them and assigns the "noclass" to one which is clicked. You can play around with "link active" as per need.
4

What you can do is use a data property to hold the currently active link. Then with that you'll be able to have any given link test if it is the active link and if the .active class should be applied.

Then it's just a matter of setting that property's new value when a link is clicked. If the same link that's currently active is clicked, then the property is cleared, thus removing the .active class from all links. Otherwise, the class is added to the link that was clicked.

This is a CodePen demonstrating what I mean in action, but your markup could look something like this:

<li><a href="#" class="link" :class="{ active: activeId == 'link-1' }"
    @click.prevent="activeLink('link-1')">Link text</a></li>

<li><a href="#" class="link" :class="{ active: activeId == 'link-2' }"
    @click.prevent="activeLink('link-2')">Link text</a></li>

<li><a href="#" class="link" :class="{ active: activeId == 'link-3' }"
    @click.prevent="activeLink('link-3')">Link text</a></li>

and your JS could look something like this:

data: {
  activeId: null
},
methods: {
  activeLink(linkIdent) {
    this.activeId = this.activeId === linkIdent ? null : linkIdent
  }
}

It's obviously not as clean a solution as it could be, but I am sticking to your requirement that the solution fit the markup you provided.

2 Comments

Thanks but is there a way to do this with an if statement? I've tried but it targets all the items not the item being clicked. jsfiddle.net/s9r4q0gc/3
The problem in your example is that there is nothing identifying which link is active. It's just setting a single isActive boolean for the entire app. You have to have some way of identifying each link and then setting a corresponding identifier to mark that link as the active one. That's what my example demonstrated. If for some reason you must use an if statement, you could simply change the body of my activeLink function to if (this.activeId === linkIdent) this.activeId = null; else this.activeId = linkIdent;
3

Here is an alternative solution that may modify your code more than you want. I thought this might be useful since you are just learning and may be interested in an alternative. I started by declaring your links as an array of objects in vue so that we can assign an active attribute to each of them. Then we can just toggle the active value inline or use the toggleActive function (not currently in use.. just there for illustration if you prefer to use functions over inline logic).

Html:

<div id="app">
  <h2>App</h2>
  <ul>
    <li v-for="l in links">
      <a href="#" class="link" :class="{ active: l.active}" @click="l.active = !l.active">{{l.text}}</a>
    </li>
  </ul>
</div>

Javascript:

var app = new Vue({
  el: '#app',
  data: {
    links: [{
      text: "Link text",
      active: false
    },{
      text: "Second text",
      active: false
    },{
      text: "Third text",
      active: false
    }]
  },
  methods: {
    //To use this function make @click in html to:
    //@click="toggleActive(l)"
    toggleActive(x) {
      x.active = !x.active;
    }
  }
})

https://jsfiddle.net/yrbt90v9/

1 Comment

Hi, thanks but I'm looking for a solution that will work with my code.
3

Use V-for and an array of items so you have no need to statically type the links. This allows for the dynamic functionality you are looking for.

  var app = new Vue({
    el: '#app',
    data: {
      links: [
       {text: "Link Text", active: false},
       {text: "Link Text", active: false},
       {text: "Link Text", active: false}
      ]
    },
    methods: {
      activate(link) {
        link.active = !link.active
      }
    }
  })
.link{
  text-decoration: none;
  color: #555;
}
.active{
  text-decoration: underline;
  color: #42b983;
}
<div id="app">
      <h2>App</h2>
      <ul>
        <li v-for="link in links"><a href="#" class="link" :class="{ active: link.active }" @click="activate(link)">Link text</a></li>
      </ul>
    </div>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.