0

I have a menu and i want to know if there is a way to Add a Class by Children class Condition.

Example:

<ul :class="{ 'open' : ThereIsClassInChild }">
    <li v-for="item in list" :class="{ 'active' : $route.name == item.routeName }">
          <a>{{ item.name }}</a>
    </li>
</ul>

I want to put the condition: the "open" class if there is "active" class inside li

@Edit

Navigation.vue

<template>
<router-link v-for="item in Menu" :to="{ name: item.KeyRouter }" tag="li" :class="{'active' : $route.name === item.KeyRouter }">
    <a>{{item.Name}}</a>
    <ul class="nav nav-second-level" v-if="item.SubMenu != null" :class="{ 'open' : isOpenComputed(item.SubMenu) }">
        <router-link :to="{ name: SecondItem.KeyRouter }" tag="li" v-for="SecondItem in item.SubMenu" :class="{ 'active': $route.name === SecondItem.KeyRouter }">
            <a>{{SecondItem.Name}}</a>
        <ul class="nav nav-third-level" v-if="SecondItem.SubMenu != null" :class="{ 'open' : isOpenComputedTwo(SecondItem.SubMenu) }">
            <router-link :to="{ name: ThirdItem.KeyRouter }" tag="li" v-for="ThirdItem in SecondItem.SubMenu" :class="{ 'active': $route.name === ThirdItem.KeyRouter }">
                <a>{{ThirdItem.Name}}</a>
            </router-link>
        </ul>
        </router-link>
    </ul>
</router-link>
</template>

<script>

let once = true
let onceTwo = true

export default {
    data: () => ({
        Menu: []
    }),
    methods: {
        isOpenComputed (Menu) {
            if(Menu === true) {
                console.log( "Menu Router 1 [ FORCED TRUE ]" )
                return true
                }
            if(once){
            console.log( "Menu Router 1 START" )
            if(Menu.find( ( i ) => this.$route.name === i.KeyRouter ) != null){
                console.log( "Menu Router 1 [ TRUE ]" )
                once = false
                return true
            } 
            console.log( "Menu Router 1 [ FALSE ]" )
        }
        },
        isOpenComputedTwo (Menu) {
            if(onceTwo){
            console.log( "Menu Router 2 [ START ]" )
            if(Menu.find( ( i ) => this.$route.name === i.KeyRouter ) != null){
            console.log( "Menu Router 2 [ TRUE ] " )
                this.isOpenComputed(true)
                onceTwo = false
                return true
            } 
            console.log( "Menu Router 2 [ FALSE ]" )
        }
        }
    },
    created() {
        let Data = [{
                "Name": "Menu 1",
                "SubMenu": [{
                    "Name": "SubMenu 1-1",
                    "KeyRouter": "Produtos"
                }]
            },
            {
                "Name": "Menu 2",
                "SubMenu": [{
                    "Name": "SubMenu 2-1",
                    "SubMenu": [{
                        "Name": "Third Page Test",
                        "KeyRouter": "PagTeste"
                    }, {

                        "Id": 5,
                        "Name": "Third Page Test 2",
                        "KeyRouter": "PagTesteTres"
                    }]
                }]
            }
        ]
        this.Menu = Data;
    }
}
</script>

My menu is generated this local object, the Routes and the class "Active" works well. I would like to put the condition to "open" class inside "ul" tag.

@FINAL EDIT - SOLUTION

I have create a second method to check if the third level page is open, check all subMenu of second level to open it.

    *<template>

    <router-link v-for="item in Menu" :to="{ name: item.KeyRouter }" tag="li" :class="{'active' : $route.name === item.KeyRouter }" :key="item.Id">
        <a>{{item.Name}}</a>
        <ul class="nav nav-second-level" v-if="item.SubMenu != null" :class="{ 'in' : isOpenComputedTwo(item.SubMenu) }">
            <router-link :to="{ name: SecondItem.KeyRouter }" tag="li" v-for="SecondItem in item.SubMenu" :class="{ 'active': $route.name === SecondItem.KeyRouter }" :key="item.Id">
                <a>{{SecondItem.Name}}</a>
            <ul class="nav nav-third-level" v-if="SecondItem.SubMenu != null" :class="{ 'in' : isOpenComputed(SecondItem.SubMenu) }">
                <router-link :to="{ name: ThirdItem.KeyRouter }"  tag="li" v-for="ThirdItem in SecondItem.SubMenu" :class="{ 'active': $route.name === ThirdItem.KeyRouter }" :key="item.Id"> 
                    <a>{{ThirdItem.Name}}</a>
                </router-link>
            </ul>
            </router-link>
        </ul>
    </router-link>

    </template>

    <script>

    let once = true
    let onceTwo = true

    export default{
    data: () => ({
       Menu: []
    )},
    methods: {
    isOpenComputed (Menu) {

        if(once){
        //console.log( "Menu Router 1 START" )
        if(Menu.find( ( i ) => this.$route.name === i.KeyRouter ) != undefined){
            console.log( "Menu Router 1 [ TRUE ]" )
            once = false
            return true
        } 
        //console.log( "Menu Router 1 [ FALSE ]" )
    } else return false

    },

    isOpenComputedTwo (Menu) {
        if(onceTwo){
        let a = false;

        if(Menu.find( ( i ) => this.$route.name === i.KeyRouter ) != null){
            onceTwo = false
            return true
        } 

        let getSubMenu = []

        if(Menu.find( ( i ) =>  i.SubMenu != undefined )) {
            Menu.find( ( i ) => { 
                getSubMenu = i.SubMenu
                for(i = 0 ; getSubMenu.length > i ; i++){
                if( getSubMenu[i].KeyRouter === this.$route.name ){
                    onceTwo = false
                    a = true;

                }
                }
            } ) 
        }
        if(a){
            return true
        }

    } else return false
    },
created() {
let Data = [{
                    "Name": "Menu 1",
                    "SubMenu": [{
                        "Name": "Página 1",
                        "KeyRouter": "Produtos"
                    }]
                },
                {
                    "Name": "Menu 2",
                    "SubMenu": [{
                        "Name": "SubMenu 2",
                        "SubMenu": [{
                            "Name": "Página 2",
                            "KeyRouter": "PaginaDois"
                        }, {
                            "Name": "Pagina 22",
                            "KeyRouter": "PaginaDoisDois"
                        }]
                    },
                    {
                        "Name": "SubMenu 3",
                        "SubMenu": [{
                            "Name": "Página 3",
                            "KeyRouter": "PaginaTres"
                        }, {
                            "Name": "Pagina 3",
                            "KeyRouter": "PaginaTresTres"
                        }]
                    },
                    ]
                }
            ]
            this.Menu = Data;
        }
    }
    </script>*

1 Answer 1

1

I would simply make a computed property to check the list data for an item with a matching route name:

computed: {
  isOpen() {
    return this.list.find((i) => this.$route.name === i.routeName)
  }
}

And use that instead:

<li v-for="item in list">
   <ul :class="{ 'open' : isOpen }">
      <li :class=" { 'active' : $route.name == item.routeName } "> 
           {{ item.name }}
      </li>
   </ul>
</li>

The same logic applies to your second scenario, but you would need to use a method instead of a computed property to keep track of the open status of each sub-menu:

methods: {
  isOpen(list) {
    return list.find((i) => this.$route.name === i.KeyRouter);
  }
}

Pass the sub-menu to the method like so:

<ul 
  class="nav nav-third-level" 
  v-if="item.SubMenu != null" 
  :class="{ 'open' : isOpen(SecondItem.SubMenu) }"
>
   <router-link 
     :to="{ name: ThirdItem.KeyRouter }" 
     tag="li" 
     v-for="ThirdItem in SecondItem.SubMenu" 
     :class="{ 'active': $route.name === ThirdItem.KeyRouter }"
   >
     <a>{{ThirdItem.Name}}</a>
   </router-link>
</ul>
Sign up to request clarification or add additional context in comments.

8 Comments

Nice Answer!! @thanksd Thanks! But can you solve my second problem? i forgot to put here! =)
I don't see why this solution wouldn't work for your second scenario since only the template has changed.
Hmm, i tryied here, and returns to me: [Vue warn]: Property or method "isOpen" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
That means you have either improperly defined the isOpen computed property or you've defined the scope of your component in a way that isOpen is being used outside of your component's template's scope. Impossible to know without seeing your code.
It doesn't look like you have tried to implement the solution in that code. What isn't working as expected?
|

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.