Switching styles using Vue Js, extracting all properties from the component

In my index.php file, I have a side-nav component structured like this:

<div class="container">
    <side-nav></side-nav>
</div>

The SideNav.vue file contains the following structure:

<template>
<div class="container">
    <nav-section name="General">
        <nav-item name="Home">
            <nav-child name="Dahsboard 1" url="#"></nav-child>
            <nav-child name="Dahsboard 2" url="#"></nav-child>
        </nav-item>

        <nav-item name="Settings">
            <nav-child name="Setting 1" url="#"></nav-child>
            <nav-child name="Setting 2" url="#"></nav-child>
        </nav-item>

        <nav-item name="Admin">
            <nav-child name="Admin 1" url="#"></nav-child>
            <nav-child name="Admin 2" url="#"></nav-child>
        </nav-item>
    </nav-section>

    <nav-section name="Data Analysis">
        <nav-item name="Data Source">
            <nav-child name="Source 1" url="#"></nav-child>
            <nav-child name="Source 2" url="#"></nav-child>
        </nav-item>

        <nav-item name="Visualization">
            <nav-child name="Chart 1" url="#"></nav-child>
            <nav-child name="Chart 2" url="#"></nav-child>
        </nav-item>

        <nav-item name="Others">
            <nav-child name="Other 1" url="#"></nav-child>
            <nav-child name="Other 2" url="#"></nav-child>
        </nav-item>
    </nav-section>
</div>
</template>

<script>
    import NavSection from './NavSection.vue'
    import NavItem from './NavItem.vue'
    import NavChild from './NavChild.vue'

    export default {
        components: {
            'nav-section':NavSection,
            'nav-item':   NavItem,
            'nav-child':  NavChild,
        },

        data() {
            return {

            }
        },

        mounted() {
            console.log('Component mounted.')
        },


    }
</script>

In the NavSection.vue file:

<template>
    <section>
        <h6>{{ name }}</h6>

        <ul>
            <slot></slot>
        </ul>
    </section>
</template>

<script>
    export default {
        props: ['name'],

        data() {
            return {

            }
        }
    }

</script>

Within NavItem.vue file:

<template>
    <li>
        <a @click="toggleClass">{{ name }}</a>

        <ul :class="{ 'active': isActive}">
            <slot></slot>
        </ul>
    </li>
</template>

<script>
    export default {
        props: ['name'],

        data() {
            return {
                isActive: false,
                names: []
            }
        },

        created() {
            //this returns all the names in console
            console.log(this.name)

        },

        methods: {

            toggleClass() {
                this.isActive = true

                // logic for switching isActive value to FALSE when another item is clicked would need to be added here
              
            }
        }

    }
</script>

Finally, in NavChild.vue:

<template>
    <li>
        <a :href="url">{{ name }}</a>
    </li>
</template>

<script>
    export default {
        props: ['name', 'url'],

        data() {
            return {

            }
        }
    }
</script>

The implementation aims to make each navSection contain multiple navItems, and each navItem house several navChild components. Upon triggering the toggleClass function by clicking on an anchor tag within a navItem, two requirements are: 1. the isActive property should update to TRUE for that specific item, and 2. isActive should revert to FALSE upon clicking on another item in the same section.

An approach suggested in the NavItem.vue file involves comparing clicked item's name prop with all names - however, finding a way to access and store all passed data for a particular prop remains unresolved. Any suggestions to enhance this code or streamline achieving the desired functionality are welcomed. Let the coding begin!

Answer №1

Instead of structuring your model within the HTML, consider adopting a model-oriented approach with Vue. Create a data model that reflects the hierarchy you desire and let your components render it.

In my application, I focused on the section level to address your concerns about lower levels. I constructed a data model similar to the initial section in your example.

The key to achieving single-selection behavior is having a variable in the parent component to store the currently selected value. This value should be managed by the parent component, and each child component should receive a prop indicating whether it is the selected value.

When a child component becomes selected, it emits an event that the parent component handles (following the Vue convention for child-to-parent communication).

Vue.component('nav-child', {
  template: '#nav-child-template',
  props: ['name', 'url']
});

Vue.component('nav-item', {
  template: '#nav-item-template',
  props: ['name', 'children', 'isActive'],
  methods: {
    toggleClass() {
      this.$emit('activate', this.isActive ? null : this.name);
    }
  }
});

new Vue({
  el: '#nav-section',
  data: {
    activeItem: null,
    items: [{
        name: 'Home',
        children: [{
            name: 'Dashboard 1',
            url: '#'
          },
          {
            name: 'Dashboard 2',
            url: '#'
          }
        ]
      },
      {
        name: 'Settings',
        children: [{
            name: 'Setting 1',
            url: '#'
          },
          {
            name: 'Setting 2',
            url: '#'
          }
        ]
      }
    ]
  },
  methods: {
    activate(name) {
      this.activeItem = name;
    }
  }
});
.active { 
  border: thin solid red; 
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<template id="nav-child-template">
    <li>
        <a :href="url">{{ name }}</a>
    </li>
</template>

<template id="nav-item-template">
    <li>
        <a @click="toggleClass">{{ name }}</a>

        <ul :class="{ 'active': isActive}">
            <li is="nav-child" v-for="child in children" :name="child.name" :url="child.url"></li>
        </ul>
    </li>
</template>

<ul id="nav-section">
  <li is="nav-item" v-for="item in items" :name="item.name" :is-active="activeItem === item.name" :children="item.children" @activate="activate"></li>
</ul>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble generating a mock constructor for the user model

While attempting to simulate my user model in order to test my service, the nest console is throwing a TypeError. I am unsure of how to properly 'emulate' the constructor of the user model. user.service.spec.ts import { Test, TestingModule } fro ...

pick out particular values from an array

I have a question that may seem basic to some, but I'm curious about how to select specific elements from an array. In this case, I have an array with 100 elements: var cubes = [element1, element2, element3 ...] and I want to select elements 25-35. ...

Guide to interacting with the Li element using JavaScript in Selenium

Is there a way to click on the item inside the li element using a Selenium script with JavaScript? I've tried different methods like By.cssSelector or by css, but I keep getting an ElementClickInterceptedError: element click intercepted:Other element ...

Display an image from the API that rotates when hovered over with the mouse

Currently, I am fetching data from pokeapi.co and dynamically inserting it into a table. This data includes various stats and an image. My goal is to make the image rotate when hovered over. While creating the table, I added an id="pokeImage" dynamically. ...

Sending data retrieved asynchronously to child components' props

Currently, I am developing an application that fetches an array of news items from a remote source and showcases them on a webpage. After successfully calling the endpoint using $.getJSON(), as indicated by console logs, I integrated this call into the pa ...

There is currently no initialized firebase.app.App instance within the Angular Application

While working on my web application with firebase mobile authentication, I encountered an issue with the recaptchaVerifier. It's giving an error when the recaptchaVerifier is not displayed. My project is already using the realtime database, which is f ...

What are the steps for initializing a session in Vue.js with Django upon a successful login?

Upon successful login, I want to redirect to a page indicating success and also include a session. How can this be achieved? I am using HTML with Vue.js for the front end and Django for the back end. Below is my Vue.js script for the login: <script> ...

Guide on Generating Dynamic JSON to Set and Retrieve Values for Forms and Displaying the Bound Values

I'm a beginner in Ionic 3 and I'm having trouble creating a page that redirects to another page without validation. I want to display the data on the new page, but it's not working. Please help! I also want to create a dynamic JSON object a ...

Leverage the power of Sass styles throughout your Vue.js project

Attempting to utilize sass globally in a vue.js app, I followed this method: const { defineConfig } = require('@vue/cli-service') module.exports = { css:{ loaderOptions:{ sass:{ data:`@import "@/sass/t ...

What is the process for enabling a deactivated hyperlink?

Trying to figure out how to create a link that will only activate when a specific value is present. Let's say I have a link like this: a(class="nav-link" id="signal_" style="pointer-events: none" href="/goToStreamingPage") <i class="fas fa-signal" ...

What is the best way to organize an array both alphabetically and by the length of its elements?

Imagine I am working with an array like this: ['a', 'c', 'bb', 'aaa', 'bbb', 'aa']. My goal is to sort it in the following order: aaa, aa, a, bbb, bb, c. this.array= this.array.sort((n1, n2) => ...

How can Observables be designed to exhibit both synchronous and asynchronous behavior?

From: Understanding the Contrasts Between Promises and Observables In contrast, a Promise consistently operates asynchronously, while an Observable can function in synchronous or asynchronous manners. This presents the opportunity to manipulate code in ...

Attempting to establish a connection between node.js and mongodb, receiving a positive response but failing to establish a successful connection

I have been working on setting up a mongodb database using mongoose in node.js by following various online tutorials. I have successfully managed to get the mongodb running and listening on port 27017. However, when I run my connection code in node.js, I a ...

Is it possible to edit the JSON file served by the API in NextJS during runtime and have the API serve the updated file?

I apologize for the wording of my question. My main struggle lies in not being able to articulate it properly, as I have searched extensively online without finding a solution. In my usage of api routes in Next.js, I am seeking to serve a data.json file. ...

Is it possible to create an online game using JavaScript?

Hey there, I'm interested in creating a simple online game that can be played in the browser. My main question is this: if I want two players to compete against each other online, can I achieve this by using HTML for the front-end and JavaScript for t ...

The value of AngularJS $scope is not defined

AngularJS is a new technology for me that I am using on my current project. However, I am facing confusion due to an error that keeps popping up. The issue lies within a JavaScript function: function ShowHideEditOptions(id) { var editOptions ...

The requested resource at http://js:port/socket.io/1/ could not be located (Error 404

Having trouble connecting with Socket.io. This is the server-side code: function chatserver(){ var express = require('express'), app = express(), server = require('http').createServer(app).listen(app.get('port'),function ...

Vuetify checkboxes group returns all checked items

I am encountering an issue where all my checkboxes are always returning true. I attempted to utilize the "false-value" attribute, but it did not provide any solution. On another note, the default input checkbox is functioning correctly. export default ...

What advantages does using an RxJS Subject have over handling multiple event listeners individually in terms of speed

After investigating a page's slow performance, I identified an angular directive as the root cause. The culprit was a piece of code that registered event listeners on the window keydown event multiple times: @HostListener('window:keydown', ...

Spacing between posts using CSS and jQuery

Currently, my code is creating a random number of new articles within the body of my webpage. I have successfully implemented different colors for each article, but I am encountering an issue with padding. Being new to web development, I am attempting to s ...