Manipulating arrays with multiple conditions using Vue.js and JavaScript

In my Vue.js application, I have implemented a navigation drawer to display the different pages accessible to users. The visibility of each page is determined by the activation status of the related module, indicated by a unique moduleID assigned to each page and its children. The list of displayed pages is populated by the array filteredPages[], which contains only the pages that the user has access to. The complete set of pages is stored in the original data source pages[].

To summarize, a page will only be displayed if both of the following conditions are met:

  1. activatedModules[] contains the moduleID of the page and its children.
  2. userPermissions[] includes the permissions value required for the children (or the page itself if there are no children).

Here is an excerpt of my code structure:

export default {
    data: () => ({
        // Pages information with their respective moduleIDs and permissions
        pages: [
            // Page "Team" containing "Dashboard" as child
            {
                text: 'Team', moduleID: 'm1',
                children: [
                    { text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' },
                ],
            },
            // Other pages with similar hierarchy and permission setup
        ],
        // Array defining activated modules
        activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
        // User permissions required for accessing certain pages
        userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50'],
        filteredPages: []
    }),
    computed: {
        filterArray() {
            // Need assistance in implementing the filtering logic here
        }
    }
}

The expected output after filtering should look like this:

filteredPages: [
    // Displayed pages based on user's permissions and activated modules
]

User permissions are managed and stored in Firebase Cloud Firestore, illustrated by the provided screenshot.

If you can assist in finalizing the filtering process for the array, it would be greatly appreciated.

Answer №1

Here is the solution:

calculated: {
  sortedItems() {
    return this.items.map(item => ({
      ...item, 
      products: item.products
        // when products exist
        ? item.products.filter(
          // filter out those not in `userPermissions`
          product => this.userPermissions.includes(product.permissions)
          // and those not in `activatedModules`
            && this.activatedModules.includes(product.moduleID)
        )
        : item.products
    })).filter(
      // keep item only if in `activatedModules` and...
      item => (this.activatedModules.includes(item.moduleID)) &&
        // if products exist and have length or...
        (item.products?.length || (
          // if products do not exist and item.permissions are in userPermissions
          !item.products && this.userPermissions.includes(item.permissions)
        ))
    );
  }
}

Check it out in action:

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',
  data: () => ({
    items: [
      {
        name: 'Shoes',
        moduleID: 'm1',
        products: [
          { name: 'Sneakers', price:'$50', permissions: 'p101', moduleID: 'm1-1' }
        ],
      }, {
        name: 'Clothing',
        moduleID: 'm2',
        products: [
          { name: 'Shirts', price:'$20', permissions: 'p201', moduleID: 'm2-1' },
          { name: 'Pants', price:'$30', permissions: 'p202', moduleID: 'm2-2' },
        ],
      }, {
        name: 'Accessories',
        moduleID: 'm3',
        products: [
          { name: 'Hats', price:'$10', permissions: 'p301', moduleID: 'm3-1' },
          { name: 'Bags', price:'$40', permissions: 'p302', moduleID: 'm3-2' },
        ],
      }, {
        name: 'Electronics',
        moduleID: 'm4',
        products: [
          { name: 'Laptops', price:'$500', permissions: 'p401', moduleID: 'm4-1' },
          { name: 'Phones', price:'$300', permissions: 'p402', moduleID: 'm4-2' },
        ],
      },
      { name: 'Miscellaneous', price:'$5', permissions: 'p50', moduleID: 'm5' }
    ],
    activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
    userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50']
  }),
  calculated: {
    sortedItems() {
      return this.items.map(item => ({
        ...item, 
        products: item.products
          ? item.products.filter(
            product => this.userPermissions.includes(product.permissions)
              && this.activatedModules.includes(product.moduleID)
          )
          : item.products
      })).filter(
        item => (this.activatedModules.includes(item.moduleID))
          && (item.products?.length || (
            !item.products && this.userPermissions.includes(item.permissions)
          ))
      );
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <pre v-html="sortedItems" />
</div>

Answer №2

Below is a snippet of code where I utilized a filter function to first filter by the activatedModules, then used a forEach loop to further filter each object's children property based on the userPermissions. You can take inspiration from this example for your Vue component or gain insights on how to address similar issues (hopefully, this provides some assistance):

const pages = [{
    text: 'Team',
    moduleID: 'm1',
    children: [{
      text: 'Dashboard',
      route: 'team/dashboard',
      permissions: 'p1382',
      moduleID: 'm1-1'
    }, ],
  },
  {
    text: 'Planner',
    moduleID: 'm2',
    children: [{
        text: 'Events',
        route: '/planner/events',
        permissions: 'p47289',
        moduleID: 'm2-1'
      },
      {
        text: 'Calendar',
        route: '/planner/calendar',
        permissions: 'p283',
        moduleID: 'm2-2'
      },
    ],
  },
  {
    text: 'HR',
    moduleID: 'm3',
    children: [{
        text: 'Staff',
        route: '/hr/staff',
        permissions: 'p34729',
        moduleID: 'm3-1'
      },
      {
        text: 'Config',
        route: '/hr/config',
        permissions: 'p382',
        moduleID: 'm3-2'
      },
    ],
  },
  {
    text: 'Admin',
    moduleID: 'm4',
    children: [{
        text: 'Users',
        route: '/admin/users',
        permissions: 'p3z4',
        moduleID: 'm4-1'
      },
      {
        text: 'Security',
        route: '/admin/security',
        permissions: 'p2u3',
        moduleID: 'm4-2'
      },
    ],
  },
  {
    text: 'Support',
    route: '/support',
    permissions: 'p332j',
    moduleID: 'm5'
  },
];
const activatedModules = ['m1', 'm3', 'm4', 'm5'];
const userPermissions = ['m1-1', 'm3-1', 'm3-2', 'm4-2'];
// This code controls my navigation drawer:
let filteredPages = null;

filteredPages = pages.filter(x => activatedModules.includes(x.moduleID));
filteredPages.forEach(x => {
 if (x.children)
  x.children = x.children.filter(y => userPermissions.includes(y.moduleID));
});

console.log(filteredPages);

Answer №3

Here are a couple of important points to consider:

  • Avoid using the function keyword for callbacks, such as in the case of filter, as it can lead to the loss of the correct this value. Instead, opt for arrow functions.
  • filter alone may not suffice for your requirements, especially when you need to create new objects with fewer children. In such cases, you should first use map to generate these narrowed down objects, followed by applying filter.

If you want to test the functionality without Vue, you can execute the below snippet which manually calls filterArray:

let app = {
    computed: {
        filterArray() {
            this.filteredPages = this.pages.map(item => {
                let children = (item.children || []).filter(child => 
                    this.activatedModules.includes(child.moduleID) &&
                    this.userPermissions.includes(child.permissions)
                );
                return (children.length || !item.children) 
                    && this.activatedModules.includes(item.moduleID)
                    && {...item, children};
            }).filter(Boolean);
        }
    },
    data: () => ({
        pages: [
            {
                text: 'Team', moduleID: 'm1',
                children: [
                { text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' },
                ],
            },
            {
                text: 'Planner', moduleID: 'm2',
                children: [
                { text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
                { text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
                ],
            },
            {
                text: 'HR', moduleID: 'm3',
                children: [
                { text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
                { text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
                ],
            },
            {
                text: 'Admin', moduleID: 'm4',
                children: [
                { text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
                { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
                ],
            },
            { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' },
        ],
        activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
        userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50'],
        filteredPages: []
    }),
};

// For demonstration purposes, we simulate the effect of calling computed.filterArray in Vue
let data = app.data();
app.computed.filterArray.call(data);
// Validate the result:
console.log(data.filteredPages);

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

Utilizing Javascript to Open a New Tab from Drupal

I'm attempting to trigger the opening of a new tab when a specific menu link is clicked within a Drupal website. My initial approach was to incorporate JavaScript directly into the content of the page, but unfortunately this method has not been succes ...

Mastering the art of square bracket destructuring in React through deep comprehension of the concept

import React, { useEffect, useState } from 'react' import { Text } from 'react-native' export default function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount((co ...

Seeking the method to obtain the response URL using XMLHttpRequest?

I'm having trouble with a page (url) that I request via XMLHttpRequest. Instead of getting a response from the requested url, the request is being directed to another page. requesting --- > page.php getting response from > directedpage.php ...

What is the best way to retrieve the values of "qty" and "price" and access them within the item [array] without knowing the IDs?

I am currently working on a shopping cart project, specifically on the "previous orders" page to display order details. My goal is to output this information in an (.ejs) file. The data structure includes nested objects, and within one object, propertie ...

Utilizing jQuery for clearing specific input fields within a WTForm

Within my Flask application, I encounter a scenario where I have a form with multiple fields. The form contains two submit buttons, with the objective of only submitting data from fields one and two, while ignoring the other fields even if they have conten ...

I'm looking for a simple method to transform the print_r or var_dump output into an array

I'm looking to transform the output of var_dump or print_r into an array that replicates the original structure. Here's the example input: stdClass Object ( [title] => Edison's Friends [status] => 1 [field_deck_owner] =& ...

include a new value to the current state array within a react component

I am working with an array in React State and I need to add a new property called Value. However, every time I try to add it, it creates a new item in the array. What I actually want is for the new property to be added as follows: value: '' Belo ...

Issue with AngularJS: error:areq Invalid Argument

<!DOCTYPE html> <html ng-app> <body data-ng-controller="SimpleController"> <div class="container"> Title: <br/> <input type="text" ng-model="title" />{{title}} <br/> ...

What is the best way to convert a circular JSON object to a string

Is there a way to stringify a complex JSON object without encountering the "Converting circular structure to JSON" error? I also need its parser. I am facing issues every time I try to use JSON.stringify and encounter the "Converting circular structure to ...

Creating a 2-dimensional array using Json in C# MVC: A step-by-step guide

Presently, I am utilizing this particular class public class FooResult { public int sEcho; public Foo[] aaData; internal FooResult() { sEcho = 1; aaData = new FooRepository().GetAll().ToArray(); } } new FooRepository() ...

Execute Jest tests exclusively on the directory you are currently in

When I run Jest on my machine by typing jest from the terminal, it automatically executes tests from parent folders as well. However, I want to only run tests from the current folder. For example, if I navigate to c:/dev/app in the terminal and enter a co ...

Arranging asynchronous functions using async/await in Node.js/JavaScript

When it comes to organizing my code in js/nodejs, I frequently rely on this pattern. (async function(){ let resultOne = await functionOne(); let resultTwo = await functionTwo(); return { resultOne: resultOne, resultTwo: resul ...

Is it possible for the $.post function to overwrite variables within the parent function?

Recently, I delved into the world of JavaScript and my understanding is quite limited at this point. So, please bear with me as I learn :-) I am working on a basic booking system that saves dates and user IDs in MySQL. The system checks if a particular da ...

Error Message "Alexa.create is not a valid function" encountered while using the Alexa HTML Web API on the Echo Show 10

Here is the HTML code for my custom Alexa Skill. <head> <script src="https://cdn.myalexaskills.com/latest/alexa-html.js"> </script> </head> <body> var alexaClient; Alexa.create({version: '1.0'}) .t ...

Troubleshoot: Firebase deployment of Vue.js application unable to locate page

I'm currently working on a silly web app with my friends for some laughs. We're using Firebase hosting and Discord OAuth2. The issue arises when attempting to access the "/login" page either by entering it in the URL or clicking "authorize" on th ...

Display a loading spinner on the browser while the form is being submitted

My current project involves using AJAX to retrieve data and populate a form. The data being fetched is quite large, resulting in a delay as it is fetched from the database and filled into the form fields. During this process, I display a loading icon to in ...

Create an immediate impact by injecting CSS

I currently have the following code set up: style.js: function applyStyle(str) { var element = document.createElement('style'); element.innerHTML = str; document.body.appendChild(element); } var style = 'body {' style ...

Animating with jQuery to a specific offset or position

Currently, I am utilizing jQuery animate to modify the location of an element: $('#item').animate({'top' : '-50'}, 0); The goal is to set the position without any animations. I experimented with both offset and position, but ...

The slides in Swiperjs are having trouble moving smoothly

I am experiencing some challenges with swiperjs where the slides are not snapping to the next slide and I am unable to fetch the active index from them. Below is a snippet of my code where I am using typescript, swiperjs version 6.84, and the Ionic frame ...

Is it possible to execute "green arrow" unit tests directly with Mocha in IntelliJ IDEA, even when Karma and Mocha are both installed?

My unit tests are set up using Karma and Mocha. The reason I use Karma is because some of the functionality being tested requires a web browser, even if it's just a fake headless one. However, most of my code can be run in either a browser or Node.js. ...