Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

davemaxwell's avatar

How to bind to a url in an object of array in vue js 3

I have an array of items with the title, icon, and url for each item in the array. So what I want is when a user clicks an item, they should be taken to the url. How do I render them successfully?

state: {

navigation: [
  
  {
    title: "Home",
    icon: "",
    url: "/"
},

  {
    title: "Pages",
    icon: "",
    url: "/pages"
},
] }

<template>
<div class="w-40 h-full fixed bg-gray-800 b-t-white text-sm font-serif font-medium antialiased text-white pl-2 pt-4 z-20">
    <ul id="navigation">
    <li v-for="(item, index) in navigation" :key="'item'+index">
        <i v-if="item.subnav" class="icon" :class="{'ChevronLeftIcon' :!item.open, 'ChevronDownIcon' :item.open }">
</i>
        <div class="title" @click="item.open = !item.open">{{item.title}}</div>
        <Dropdown v-if="item.subnav" :list="item" />
        </li>
    </ul>
</div>
</template>

<script>
import Dropdown from './Dropdown.vue'
export default {
    components:{Dropdown},
computed:{
  navigation(){
    return this.$store.getters.navigation;
  }
}
}
</script>

I have tried wrapping the rendered item element with the router-link component and using the :to prop to navigate to the target url

But I get the following errors: (1) "item" was accessed during render but is not defined on instance & (2) Cannot read properties of undefined (reading 'url'). Please any help on how to fix this will be highly appreciated thanks.
0 likes
13 replies
ramonrietdijk's avatar

Could you format your code, please? This can be done using three grave accents.

``` your code ```

Will turn into

your code
1 like
ramonrietdijk's avatar

@davemaxwell Where exactly are you using the url property of an item, in the Dropdown component?

When you render your dropdown, you check if the subnav of an item is available. However, you bind the item to the list property instead of the subnav. Is that correct?

<Dropdown v-if="item.subnav" :list="item.subnav" />
davemaxwell's avatar

@ramonrietdijk

  <div class="pl-3">
    <ul v-show="list.open">
        <li v-for="(item, index) in list.subnav" :key="'item' +index">

            <div class="title" @click="item.open = !item.open">{{item.title}}</div>

            <Dropdown v-if="item.subnav" :list="item" />
        </li>
    </ul>
  </div>
</template>```
ramonrietdijk's avatar

@davemaxwell Your code looks fine, assuming your subnav properties are structured the same way.

Does the code still cause the following error message? (If so, is it caused by the dropdown?)

"item" was accessed during render but is not defined on instance

Also, where exactly have you put the <router-link> element, as your templates does not contain any.

davemaxwell's avatar

@ramonrietdijk Sorry for the inconsistency, I have also been trying to fix it. I have earlier place the router-link like below

        <li v-for="(item, index) in navigation" :key="'item'+index">
        <router-link :to="item.url">
            <i v-if="item.subnav" class="icon" :class="{'ChevronLeftIcon' :!item.open, 'ChevronDownIcon' :item.open }"></i>
            <div class="title" @click="item.open = !item.open">{{item.title}}</div>
            <Dropdown v-if="item.subnav" :list="item" />
        </router-link>
        </li>
    </ul>```
ramonrietdijk's avatar

@davemaxwell No problem!

Does every item in your navigation and subnav contain a url property? If not, it may be caused because of that.

However, I can also see that you have nested your Dropdown component within the <router-link>. This will cause <a> tags within <a> tags. Would it work if you tried something like the following:

<ul>
    <li v-for="(item, index) in navigation" :key="'item'+index">
        <i v-if="item.subnav" class="icon" :class="{'ChevronLeftIcon' :!item.open, 'ChevronDownIcon' :item.open }"></i>
        <router-link v-if="item.url" :to="item.url">separated link</router-link>
        <div class="title" @click="item.open = !item.open">{{item.title}}</div>
        <Dropdown v-if="item.subnav" :list="item" />
    </li>
</ul>
davemaxwell's avatar

@ramonrietdijk @ramonrietdijk Thanks very much, I really appreciate your time and patience to guide me gradually through this. The above method really worked. I discovered that if I use the <router-link v-if="item.url" :to="item.url"></router-link> items with subnav are been filtered out thereby displaying only the items with the url class. For example, I have some items like the below:

        title: "Pages",
        icon: "",
        url: "/pages"
    },
      
      {
        title: "Posts",
        icon: "",
        poen: true,
        subnav:[
          {
            title: "Published",
            icon: "",
            url: ""
        },

Only the title Page is been displayed and Posts is not because it doesn't have the url class. Please if you have any Idea about solving this I will be very grateful.

ramonrietdijk's avatar

@davemaxwell If I understand it correctly, an item has either a url or subnav.

Perhaps something like this would work for you:

<ul>
    <li v-for="(item, index) in navigation" :key="'item'+index">
        <router-link class="title" v-if="item.url" :to="item.url">{{item.title}}</router-link>
        <template v-if="item.subnav">
            <i  class="icon" :class="{'ChevronLeftIcon' :!item.open, 'ChevronDownIcon' :item.open }"></i>
            <div class="title" @click="item.open = !item.open">{{item.title}}</div>
            <Dropdown :list="item" />
        </template>
    </li>
</ul>

I have added a <template> to wrap your subnav check so we only have to define it once. The template tag itself won't show up on the front-end. Notice that I also have added class="title" to the <router-link> element.

1 like

Please or to participate in this conversation.