1

I'm trying to access an anchor element in a computed property in order to determine whether is should be set to active or remain as is.

I've seen examples using v-for and looping through data properties, but this is a static menu like so:

<template>
<div class="panel panel-default">
    <div class="panel-heading">Application Menu</div>
    <ul class="list-group">
        <a :href="route('applications.index')" 
           :class="activeClass" 
           class="list-group-item">Applications</a>
        <a :href="route('applications.repository')" 
           :class="" 
           class="list-group-item">Token Repository</a>
        <a :href="route('applications.notifications')" 
           :class="" 
           class="list-group-item">Notifications</a>
    </ul>
</div>
</template>

My activeClass computed prop would compare the href of the current anchor to the current location of the browser and return active if they match.

I've consulted all the documentation on the Vue website and Googled extensively, and I've not yet found a way to access the href attribute of the anchor calling the computed property.

3 Answers 3

2

You can't do that, and here's why. A computed property should be universal. That is to say, its value is not determined by who is accessing it. If you access this.activeClass from inside a method, its value should be the same as activeClass inside a template, assuming the state information it depends on is the same. (And who is accessing it is not state information)

If you're using Vue-Router, you can however just compare the value of $route.path and use a different class. For example:

<a :href="route('applications.index')" 
   :class="$route.path === 'whatever' ? 'active-class' : 'inactive-class'">Applications</a>
Sign up to request clarification or add additional context in comments.

Comments

2

You are thinking about it wrong. You should not be trying to access the attributes of DOM elements as if they are data. The DOM is not a data store. Data should be in your viewmodel and be used in the DOM.

You should have an array of objects that describe your items. (Also, the only permitted children of a ul are li.) You could do something like this:

<ul class="list-group">
    <li v-for="item in menuItems">
      <a :href="item.route" 
         :class="isActive(item)" 
         class="list-group-item">{{model.label}}</a>
    </li>
</ul>

If you want to have a computed that works for each of your items, you would need to make a component for each item. See vuejs using computed property for array elements

1 Comment

I could easily switch that out to a dev, either renders the same in chrome. Furthermore there is no model for this, it's a basic Laravel partial that renders a vue component. Thanks though.
1

Final solution:

<template>
<div class="panel panel-default">
    <div class="panel-heading">Application Menu</div>
    <ul class="list-group">
        <a :href="route('applications.index')" 
           :class="activeClass('applications')" 
           class="list-group-item">Applications</a>
        <a :href="route('applications.repository')" 
           :class="activeClass('repository')" 
           class="list-group-item">Token Repository</a>
        <a :href="route('applications.notifications')" 
           :class="activeClass('notifications')" 
           class="list-group-item">Notifications</a>
    </ul>
</div>
</template>

<script>

export default {
    data () {
        return {
            currentLink: location.href,
        }
    },
    computed: {
        routes() {
            return window.routes
        },
    },
    mounted() {
        this.setCurrentLink()
    },
    methods: {
        route(url) {
            return this.routes.route(url)
        },
        activeClass(segment) {
            return segment == this.currentLink ? 'active' : ''
        },
        setCurrentLink() {
            this.currentLink = new URL(location.href).pathname.split('/').pop();
        }
    }
}
</script>

Works perfectly without the need to iterate through a loop. I call this a rare use case, but for something small and static it fits the bill.

Thanks to all who contributed.

Comments

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.