Cannot read properties of undefined (reading 'map'). Why do I get this when trying to use function twice?

I have a component containing an array, which has certain categories and headers. I wanted to put these into a collapsible menu, but ran into trouble because since all the items are in a single array, I only had the option of toggling every item, so my solution was to split up the array into two, so I could seperate the categories for toggling, but when doing so I am getting the following error “Cannot read properties of undefined (reading ‘map’)”

Here I will show you the code and where the error occurs.

So this is my array. As you can see I have mainLinkGroups and mainLinkGroupsTwo that I pass to my tools menu component.

<template>
  <div>
<tools-menu ref="toolsMenu" :main-link-groups="mainLinkGroups"/>
<tools-menu ref="toolsMenu" :main-link-groups-two="mainLinkGroupsTwo"/>
  </div>
</template>

<script>
  import icons from '@/models/entity/icon';
  import ToolsMenu from '@/components/navbar/ToolsMenu';
  
  export default {
components: {
  ToolsMenu,
      },

computed: {
  mainLinkGroups() {
    return [
      {
        header: 'HeaderOne',
        icon: icons.HOME,
        links:   [
          {
            icon: 'fas fa-copy',
            text: 'Foo',
            area: 'ONE'
          }       
                ]
  },
  mainLinkGroupsTwo() {
    return [
      {
        header: 'HeaderTwo',
        links:  [
          {
            to: '/home',
            icon: 'fas fa-home',
            text: 'home',
            area: 'TWO'
          },
               ]
  }
},
methods: {
  showTools() {
    this.$refs.toolsMenu.show();
  }
}
  };
</script>

This the Tool menu where the arrays are used.

<template>
  <b-modal
    id="tools-modal"
    v-model="visible"
    modal-class="main-menu-modal"
    size="lg"
    :hide-footer="small"
    @show="refreshNodes"
    scrollable
    hide-header
      >
    <b-row class="h-100">
      <b-col class="h-100" >

     
          <template v-for="(linkGroup, index) in filteredLinkGroups">
            <b-col v-b-toggle.collapse2  class="group-header">
              <div class="header-icon" v-if="linkGroup.header.includes('HeaderOne')">
                <i class="fas fa-list fa-lg"></i>
              </div>
              <h4 class="header-title">{{$t(linkGroup.header)}}</h4>
            </b-col>
            <b-collapse id="collapse1">
            <b-row cols="3" cols-sm="4" cols-lg="4" @click="visible = false" no-gutters>
              <b-col v-for="link in linkGroup.links" style="padding: 0 1rem 1rem;">
                <b-link :to="link.to" @click="clickLink(link)">
                  <b-aspect>
                    <b-card body-class="text-center d-flex flex-column align-items-center justify-content- 
       center" id="menu-card">
                      <div><i class="fa-fw fa-xl" :class="link.icon"/></div>
                      <div style="line-height: 1.5em; min-height: 3em;" class="d-flex align-items-center">{{ 
         $t(link.text) }}</div>
                    </b-card>
                  </b-aspect>
                </b-link>
              </b-col>
            </b-row>
            </b-collapse>
          </template>

             <template v-for="(linkGroup, index) in filteredLinkGroupsTwo">
            <b-col v-b-toggle.collapse3  class="group-header">
              <div class="header-icon" v-if="linkGroup.header.includes('HeaderTwo')">
                <i class="fas fa-building fa-lg"></i>
              </div>
              <h4 class="header-title">{{$t(linkGroup.header)}}</h4>
            </b-col>
            <b-collapse id="collapse4">
              <b-row cols="3" cols-sm="4" cols-lg="4" @click="visible = false" no-gutters>
                <b-col v-for="link in linkGroup.links" style="padding: 0 1rem 1rem;">
                  <b-link :to="link.to" @click="clickLink(link)">
                    <b-aspect>
                      <b-card body-class="text-center d-flex flex-column align-items-center justify-content- 
  center" id="menu-card">
                        <div><i class="fa-fw fa-xl" :class="link.icon"/></div>
                        <div style="line-height: 1.5em; min-height: 3em;" class="d-flex align-items-center">{{ 
    $t(link.text) }}</div>
                      </b-card>
                    </b-aspect>
                  </b-link>
                </b-col>
              </b-row>
            </b-collapse>
          </template>
      </b-col>
    </b-row>
      </b-modal>
    </template>

    <script>
      import icons from '@/models/entity/icon';
      import utils from '@/utils/utils';
      import {mainMenuService} from '@/services/areas/main-menu';
      import {userService} from '@/services/user';
      import LoadingMessage from '@/components/LoadingMessage';
      import {EventBus, Events} from '@/utils/event-bus';
      import {systemService} from '@/services/system';

      const urlMap = {
    COMPANY: 'companies',
    PROPERTY_OWNER: 'property-owners',
    PROPERTY: 'properties',
    UNIT: 'units',
    TENANCY: 'tenancies'
      };


      export default {
    components: {
      LoadingMessage,
    },
    props: {
      mainLinkGroups: Array,
      mainLinkGroupsTwo: Array
    },
    data() {
      return {
        icons,
        pageHistory: [],
        breadcrumb: null,
        visible: false,
        nodes: null,
        userNavigationSettings: null,
        userAreaPermissionMap: {},
      };
    },
    computed: {
      small() {
        return ['xs', 'sm', 'md'].includes(this.$mq);
      },
      filteredLinkGroups() {
        return this.mainLinkGroups.map(linkGroup => ({header: linkGroup.header, links: 
linkGroup.links.filter(item => {
            const userAreaPermission = this.userAreaPermissionMap[item.area];
            return !item.area || userAreaPermission &&
              (item.modal ? userAreaPermission === 'FULL_CONTROL' : userAreaPermission !== 
'NOT_ALLOWED');
          })}));
      },
      filteredLinkGroupsTwo() {
        return this.mainLinkGroupsTwo.map(linkGroup => ({header: linkGroup.header, links: 
linkGroup.links.filter(item => {
            const userAreaPermission = this.userAreaPermissionMap[item.area];
            return !item.area || userAreaPermission &&
                (item.modal ? userAreaPermission === 'FULL_CONTROL' : userAreaPermission !== 
'NOT_ALLOWED');
          })}));
      },
    },
    methods: {
      clickLink(link) {
        this.visible = false;
        if (link.click) {
          link.click();
        }
      },
      show() {
        this.visible = true;
      },

      refreshNodes() {
        if (this.visible) {
          this.breadcrumb = null;
          this.nodes = null;
         
      };
    </script>

The error happens when I try to duplicate the filtered function

filteredLinkGroups() {
        return this.mainLinkGroups.map(linkGroup => ({header: linkGroup.header, links: 
linkGroup.links.filter(item => {
            const userAreaPermission = this.userAreaPermissionMap[item.area];
            return !item.area || userAreaPermission &&
              (item.modal ? userAreaPermission === 'FULL_CONTROL' : userAreaPermission !== 
'NOT_ALLOWED');
          })}));

filteredLinkGroupsTwo() {
        return this.mainLinkGroupsTwo.map(linkGroup => ({header: linkGroup.header, links: 
linkGroup.links.filter(item => {
            const userAreaPermission = this.userAreaPermissionMap[item.area];
            return !item.area || userAreaPermission &&
              (item.modal ? userAreaPermission === 'FULL_CONTROL' : userAreaPermission !== 
'NOT_ALLOWED');
          })}));

If I delete either filteredLinkGroups or filteredLinkGroupsTwo I get no error, but when I try to use them together I get the Cannot read properties of undefined (reading ‘map’) error. I can’t figure out why.

How do I solve this?

I’d start by cleaning up all the duplicate code. You shouldn’t need 2 sets of functions and computed (you shouldn’t be using computed at all for this purpose really). You also can’t have 2 refs of the same name. The ref should be in a loop, which you can then access as an array.

This is just a design problem. All you need to do is model your data so that each set can be enabled separately.

Something along these lines,

data () {
  return {
    linkGroups: [
      {
        expanded: false,
        header: 'HeaderOne',
        icon: icons.HOME,
        links: [
          {
            icon: 'fas fa-copy',
            text: 'Foo',
            area: 'ONE'
          }       
        ]
      },
      {
        expanded: false,
        header: 'HeaderTwo',
        links: [
          {
            to: '/home',
            icon: 'fas fa-home',
            text: 'home',
            area: 'TWO'
          },
        ]
      }
    ]
  }
}