Negi Rox
Negi Rox

Reputation: 3922

Using Vue Js Data Binding is taking a time

I am new to Vue JS. So I just made one component which is repeating a section like a grid. but my problem is when I add dropdown in a grid it is taking too much time. Records may be increased next time then load time will also increase so I am looking for a solution so page load time will decrease. Here is a sample which I am using in my code.

var obj = [];
for (var i = 0; i < 4000; i++) {
    var subobj = [];
    for (var j = 0; j < 100; j++) {
        subobj.push({
            id: j,
            name: 'mukesh'
        })
    }
    var newobj = {
        'Year': 2018,
        'Month': 01,
        'Sale': 512,
        drp: subobj,
        name: "negi"
    }
    obj.push(newobj);
}
new Vue({
    el: "#tableDemo",
    data: {
        sales: obj
    }
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<div id="tableDemo">
    <table class="table table-striped">
        <thead>
            <tr>
                <th>Month</th>
                <th>Sale</th>
                <th>Customer</th>
				 <th>Customer</th>
				  <th>Customer</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="(sale,i) in sales" :key="i">
                <th scope="row">{{ sale.Month  }}</th>
                <td>{{ sale.Sale }}</td>
                <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
				 <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
				 <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
            </tr>
        </tbody>
    </table>
    <label class="control control--checkbox">
        First checkbox
        <input type="checkbox" checked="checked" />
        <div class="control__indicator"></div>
    </label>
</div>

Upvotes: 0

Views: 485

Answers (2)

Negi Rox
Negi Rox

Reputation: 3922

Hi After doing lots of R&D I found one solution. i.e. vuetify in Vue js. It's working like a Charm. I have added 50000 rows and it's rendering in 4 sec. you can increase data up to 500000 and it will hardly take 10 sec. As you can see current complexity to render a data is 50000* 300

"use strict";

var d = new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: function data() {
    return {
      items: [],
      drpItems: [],
      itemsPerPage: 0,
      optionsLength: 6,
      loading: true,
      footerProps: {
        'items-per-page-options': [10, 20, 50, 100, 1000]
      },
      headers: [{
        text: 'ID',
        value: 'id'
      }, {
        text: 'Description',
        value: 'description'
      }, {
        text: 'QTY1',
        value: 'qty1'
      }, {
        text: 'QTY2',
        value: 'qty2'
      }, {
        text: 'Qty3',
        value: 'qty3'
      }],
      customer: {
        name: 'customer',
        items: []
      }
    };
  },
  created: function created() {
    this.initialize();
    var self = this;

    window.onresize = function (event) {
      self.updateTable();
    };
  },
  methods: {
    updateTable: function updateTable() {
      var tableHeight = document.getElementById('dataTable').offsetHeight;
      this.itemsPerPage = parseInt(tableHeight / 40);
      if (this.customer.items.length < this.itemsPerPage) this.itemsPerPage = this.customer.items.length;

      if (!this.footerProps['items-per-page-options'].includes(this.itemsPerPage)) {
        if (this.footerProps['items-per-page-options'].length == this.optionsLength) {
          this.footerProps['items-per-page-options'].unshift(this.itemsPerPage);
        } else {
          this.footerProps['items-per-page-options'].shift();
          this.footerProps['items-per-page-options'].unshift(this.itemsPerPage);
        }
      }
    },
    initialize: function initialize() {
      var self=this;
      for (var i = 0; i < 300; i++) {
        this.drpItems.push("mukesh" + i);
      }

      for (var i = 0; i < 50000; i++) {
        var obj = {
          id: i,
          description: 'ABC',
          qty1: '',
          qty2: 'mukesh14',
          qty3: 'mukesh1'
        };
        obj.drpItems = [];
        this.customer.items.push(obj);
    
      } // deep copy is the solution
      // const items = JSON.parse(JSON.stringify(this.customer.items))


      this.items = this.customer.items;
      setTimeout(function(){    self.loading=false;},1500);
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" type="text/css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" type="text/css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" type="text/css" rel="stylesheet" />
<style>
#dataTable .v-table tbody tr:not(:last-child) {
    border-bottom: none;
}
#dataTable th{
 font-size:16px;
 color:"black"
}
.v-data-table__wrapper{
  border:1px solid;
}
</style>
 <v-data-table
        must-sort
        :headers="headers"
        :pagination.sync="pagination"
        :rows-per-page-items="pagination.rowsPerPageItems"
        :total-items="pagination.totalItems"
        :loading="loading"
        :items="items"
        class="elevation-1"
      >
<div id="app">
<div>
  <v-app>
    <v-main>
      <v-container>
        <v-data-table id="dataTable" dense
          :headers="headers"
          :items="items"
          :rows-per-page="itemsPerPage"
          :footer-props="footerProps"
          :loading="loading" loading-text="Loading... Please wait"
        >
     
      </template>
          <template v-slot:item.qty1="props">
            <v-text-field v-model="props.item.qty1"></v-text-field>
          </template>
          <template v-slot:item.qty2="props">
            <v-select
            :items="drpItems"
            label="Standard"
            v-model="props.item.qty2"
            :value="props.item.qty2"
          ></v-select>  
        
           </template>  
            
          <template v-slot:item.qty3="props">
            <v-select
            :items="drpItems"
            label="Standard"
            :value="props.item.qty3"
            v-model="props.item.qty3"></v-select>  
        
           </template>  
       
        </v-data-table>
      </v-container>
    </v-main>
  </v-app>
  </div>
</div>

Upvotes: 0

bricksphd
bricksphd

Reputation: 177

You are creating 4000*3 select elements with 100 option elements each. Consider the following code which is library agnostic. It has a comparable runtime to the posted VueJS code.

for(let i = 0; i < 4000 * 3; i++){
    let select = document.createElement("select");
    document.body.appendChild(select);
    for(let j = 0; j < 100; j++){
        let option = document.createElement("option");
        option.text="mukesh";
        select.add(option);
    }
}

An alternative would be to let the user select which of the 4000 sales they wanted first and then allow the user to make the selections. CodePen

HTML

<div id="tableDemo">
    <select v-model="selected_sale">
        <option v-for="(sale,i) in sales" :key="i">
            {{i}}
        </option>
    </select>
    {{selected_sale}}
     <table class="table table-striped">
        <thead>
            <tr>
                <th>Month</th>
                <th>Sale</th>
                <th>Customer</th>
                <th>Customer</th>
                <th>Customer</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th scope="row">{{ sale.Month  }}</th>
                <td>{{ sale.Sale }}</td>
                <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
                <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
                <td>
                    <select v-model="sale.name">
                        <option value="--Selected--">--Select--</option>
                        <option v-for="d in sale.drp" :value="d.name">{{d.name}}</option>
                    </select>
                </td>
            </tr>
        </tbody>
    </table>
    <label class="control control--checkbox">
        First checkbox
        <input type="checkbox" checked="checked" />
        <div class="control__indicator"></div>
    </label>
</div>

JS

let start = Date.now();
    var obj = [];
    for (var i = 0; i < 4000; i++) {
        var subobj = [];
        for (var j = 0; j < 100; j++) {
            subobj.push({
                id: j,
                name: 'mukesh'+j
            })
        }
        var newobj = {
            'Year': 2018,
            'Month': i,
            'Sale': 512,
            drp: subobj,
            name: "negi"
        }
        obj.push(newobj);
    }
    let end = Date.now();
    console.log(end - start);
    new Vue({
        el: "#tableDemo",
        data: {
            sales: obj,
            selected_sale:0,
        },
        computed:{
            sale(){
                return this.sales[+this.selected_sale];
            }
        }
    })

Upvotes: 1

Related Questions