How to insert text search field for each table header for multi search function dynamically with v-for?

438 Views Asked by At

In order to achieve for multi search function we add a search field at each header with v-slot where we define the header name directly. For example:

      <template v-slot:header.NAME="{ header }">
        {{ header.text }}
        <v-menu offset-y :close-on-content-click="false">
          <template v-slot:activator="{ on, attrs }">

            <v-text-field v-bind="attrs" v-on="on"
              v-model="nameSearch"
              class="pa"
              type="text"
            ></v-text-field>
          </template>         
        </v-menu>
      </template>  

Now I have around 50 headers for my data table. My idea is to render dynamically. I tried with v-for but neither it renders and or give any error. Code below:

        <template v-for="(x, index) in this.headers" slot="headers" slot-scope="props">
        {{ props.x.text }}
        <v-menu  offset-y :close-on-content-click="false" :key="index">
          <template v-slot:activator="{ on, attrs }">


            <v-text-field v-bind="attrs" v-on="on"
              v-model="searchObj"
              class="pa"
              type="text"
            ></v-text-field>

          </template>
          
        </v-menu>
      </template>  

what did i missed here ? or it is completely wrong way i went ?

Below is the full code:

    <template>
      <v-app class="main-frame">
      <v-main>
            <v-data-table
              :headers="headers"
              :items="filteredData"
            >
              <template v-slot:header.NAME="{ header }">
                {{ header.text }}
                <v-menu offset-y :close-on-content-click="false">
                  <template v-slot:activator="{ on, attrs }">

                    <v-text-field v-bind="attrs" v-on="on"
                      v-model="nameSearch"
                      class="pa"
                      type="text"
                    ></v-text-field>

                  </template>
                  
                </v-menu>
              </template>        

              <template v-slot:header.DEPARTMENT="{ header }">
                {{ header.text }}
                <v-menu offset-y :close-on-content-click="false">
                  <template v-slot:activator="{ on, attrs }">


                    <v-text-field v-bind="attrs" v-on="on"
                      v-model="departmentSearch"
                      class="pa"
                      type="text"
                    ></v-text-field>

                  </template>
                  
                </v-menu>
              </template>  

          </v-data-table>
      </v-main>
      </v-app>
    </template>

    <script>

    import axios from "axios";

    }
    export default {
      name: 'Home',

      data() {
        return {
        /* Table data */ 
          headers: []
          allData: [],

          /* Column Search */
          nameSearch: '',
          departmentSearch: ''

        }
      },

      computed: {

        filteredData() {
          
          let conditions = [];
          
          if (this.nameSearch) {
            conditions.push(this.filterName);
          }

          if (this.departmentSearch) {
            conditions.push(this.filterDepartment);
          }
          
          if (conditions.length > 0) {
            return this.allData.filter((data) => {
              return conditions.every((condition) => {
                return condition(data);
              })
            })
          }
          
          return this.allData;
        }
      },


      mounted () {
        this.getAllData() 
      },

      methods: {
        getAllData() {
        this.allData = []

        axios
          .get("http://localhost:5001/"}
          .then(res => {
            if (res.status === 200) {
              if (res.data === 0) {
                console.log("Something is wrong !!!")
              } else {
                this.allData = res.data["allData"]

                this.headers = res.data["allDataHeaders"]

              }
            }
          
          }).catch(error => {
            console.log(error);
            
          })
      },

      filterName(item) {
          return item.NAME.toLowerCase().includes(this.nameSearch.toLowerCase())
      },

      filterDepartment(item) {
          return item.DEPARTMENT.toLowerCase().includes(this.departmentSearch.toLowerCase())
      },
        
    }
      
    }
    </script>
1

There are 1 best solutions below

0
On BEST ANSWER

I have found the solution myself:

        <template v-for="(header, i)  in headers" v-slot: 
        [`header.${header.value}`]="{  }"> 
        <div @click.stop :key="i">
         {{ header.text }}
            <v-text-field :key="i"
              v-model="multiSearch[header.value]"
              class="pa"
              type="text"
              :placeholder="header.value"
              prepend-inner-icon="mdi-magnify"
            ></v-text-field>
         </div>
        </template>

In data, I have an empty object called:

searchObj: {}

and in computed method, i have the following method:

filteredData() {

  if (this.searchObj) {
    return this.allData.filter(item => {
      return Object.entries(this.searchObj).every(([key, value]) => {

        return (item[key] || '').toLowerCase().includes(value.toLowerCase())
        
      })
    })
  } else {
    return this.allData
  } 
},

Full solution below:

  <template>
  <v-app class="main-frame">
  <v-main>
        <v-data-table
          :headers="headers"
          :items="filteredData"
        >

        <template v-for="(header, i)  in headers" v-slot: 
         [`header.${header.value}`]="{  }"> 
         {{ header.text }}
          <div @click.stop :key="i">
            <v-text-field :key="i"
              v-model="multiSearch[header.value]"
              class="pa"
              type="text"
              :placeholder="header.value"
              prepend-inner-icon="mdi-magnify"
            ></v-text-field>
          </div>
        </template>

      </v-data-table>
  </v-main>
  </v-app>
</template>

<script>

import axios from "axios";

}
export default {
  name: 'Home',

  data() {
    return {
    /* Table data */ 
      headers: []
      allData: [],
      searchObj: {},
    }
  },

  computed: {

    filteredData() {

      if (this.searchObj) {
        return this.allData.filter(item => {
          return Object.entries(this.searchObj).every(([key, value]) => {

             return (item[key] ||'').toLowerCase().includes(value.toLowerCase())

             })
        })
      } else {
          return this.allData
        } 
     },
  },


  mounted () {
    this.getAllData() 
  },

  methods: {
    getAllData() {
    this.allData = []

    axios
      .get("http://localhost:5001/"}
      .then(res => {
        if (res.status === 200) {
          if (res.data === 0) {
            console.log("Something is wrong !!!")
          } else {
            this.allData = res.data["allData"]

            this.headers = res.data["allDataHeaders"]

          }
        }
      
      }).catch(error => {
        console.log(error);
        
      })
  },

}
  
}
</script>