justalever
justalever

Reputation: 11

Vue JS nested loop search not returning results

I'm building a key-command resource and giving VueJS a whirl while doing so. I'm a newbie but am gaining the grasp of things (slowly...).

I want to be able to search in a global search form for key commands I'm defining as actions within sections of commands (see data example below). I would like to search through all the actions to show only those that match the search criteria.

My HTML is below:

<div id="commands">

  <input v-model="searchQuery" />

  <div class="commands-section" v-for="item in sectionsSearched" 
:key="item.id">

    <h3>{{ item.section }}</h3>

    <div class="commands-row" v-for="command in item.command" :key="command.action"> 
          {{ command.action }}
    </div>

  </div>
</div>

My main Vue instance looks like this:

import Vue from 'vue/dist/vue.esm'
import { commands } from  './data.js'

document.addEventListener('DOMContentLoaded', () => {

  const element = document.getElementById("commands")

  if (element != null) {

  const app = new Vue({
    el: element,
    data: {
      searchQuery: '',
      commands: commands
    },
    computed: {
      sectionsSearched() {
        var self = this;
        return this.commands.filter((c) => {
          return c.command.filter((item) => {
            console.log(item.action)
            return item.action.indexOf(self.searchQuery) > -1;
           });
          });
        },
      }
    });
  }
});

And finally the data structure in data.js

const commands = [
  {
     section: "first section",
     command: [
       { action: '1' },
       { action: '2' },
       { action: '3' },
     ],
  },
  {
     section: "second section",
     command: [
       { action: 'A' },
       { action: 'B' },
       { action: 'C' },
     ]
  },  
]

export { commands };

I'm able to output the commands using the console.log(item.action) snippet you see in the computed method called sectionsSearched.

I see no errors in the browser and the data renders correctly.

I cannot however filter by searching in real-time. I'm nearly positive it's a combination of my data structure + the computed method. Can anyone shed some insight as to what I'm doing wrong here?

I'd ideally like to keep the data as is because it's important to be sectioned off.

I'm a Rails guy who is new to this stuff so any and all feedback is welcome.

Thanks!

EDIT

I've tried the proposed solutions below but keep getting undefined in any query I pass. The functionality seems to work in most cases for something like this:

 sectionsSearched() {
      return this.commands.filter((c) => {
        return c.command.filter((item) => {
          return item.action.indexOf(this.searchQuery) > -1;
         }).length > 0;
      });
    },

But alas nothing actually comes back. I'm scratching my head hard.

Upvotes: 1

Views: 253

Answers (3)

Blake Woo
Blake Woo

Reputation: 33

sectionsSearched() {
    return this.commands.filter((c) => {
      return c.command.filter((item) => {
        return item.action.indexOf(this.searchQuery) > -1;
       }).length > 0;
    });
    },
  }

since filter will always return an array(empty or not) which value always is true.

Upvotes: 0

MinimalistYing
MinimalistYing

Reputation: 356

const commands = [
  {
     section: "first section",
     command: [
       { action: '1' },
       { action: '2' },
       { action: '3' },
     ],
  },
  {
     section: "second section",
     command: [
       { action: 'A' },
       { action: 'B' },
       { action: 'C' },
     ]
  },  
]

const element = document.getElementById("commands")

  if (element != null) {

  const app = new Vue({
    el: element,
    data: {
      searchQuery: '',
      commands: commands
    },
    computed: {
      sectionsSearched() {
        var self = this;
        return this.commands.filter((c) => {
        
         // the code below return an array, not a boolean
         // make this.commands.filter() not work
         
         // return c.command.filter((item) => {
         //   return item.action.indexOf(self.searchQuery) > -1;
         //  });
         
         // to find whether there has command action equal to searchQuery
          return c.command.find(item => item.action === self.searchQuery);
         });
        },
      }
    });
  }
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="commands">

  <input v-model="searchQuery" />

  <div class="commands-section" v-for="item in sectionsSearched" 
:key="item.id">

    <h3>{{ item.section }}</h3>

    <div class="commands-row" v-for="command in item.command" :key="command.action"> 
          {{ command.action }}
    </div>

  </div>
</div>

Is that work as you wish ?

Upvotes: 0

void
void

Reputation: 36703

There is a issue in your sectionsSearched as it is returning the array of just commands.

See this one

sectionsSearched() {
  return this.commands.reduce((r, e) => {
    const command = e.command.filter(item => item.action.indexOf(this.searchQuery) > -1);
    const section = e.section;
    r.push({
      section,
      command
    });
  }, []);
}

Upvotes: 1

Related Questions