deadbeforesunlight
deadbeforesunlight

Reputation: 229

exporting bootstrap table to excel or pdf

I'm using bootstrap vue table and I've want to export a bootstrap table to excel or pdf. It's like a table inside a table and I'm finding it difficult as to how to export it for downloading as excel or pdf as the other solutions I have come around are all involve just giving the json data and it does the work but can't find any solution regarding my problem.

Codesandbox demonstration

<template>
  <div id="app">
    <b-button @click="exportTable" class="mb-3">Export</b-button>
    <b-table-simple outlined id="htmltable">
      <b-thead class="b-table__head">
        <b-tr>
          <b-th class="small-tab">Goods</b-th>
          <b-th>Units</b-th>
          <b-th>Price Per Unit</b-th>
          <b-th>Total Price</b-th>
        </b-tr>
      </b-thead>
      <b-tbody v-for="(service, index) in goodsGroupedByCategory" :key="index">
        <b-tr class="category-line">
          <b-th class="small-tab cs-textstyle-paragraph-small-bold">{{
            index
          }}</b-th>
          <b-td></b-td>
          <b-td></b-td>
          <b-th class="cs-textstyle-paragraph-small-bold">{{
            service.reduce(function (prev, curr) {
              return prev + curr.total_units * curr.price_per_unit;
            }, 0)
          }}</b-th>
        </b-tr>
        <b-tr
          v-for="serviceItem in service"
          :key="serviceItem.id"
          class="item-line"
        >
          <b-td class="big-tab cs-textstyle-paragraph-small">{{
            serviceItem.billing_sku_name
          }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
            serviceItem.total_units
          }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
            serviceItem.price_per_unit
          }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
            serviceItem.total_units * serviceItem.price_per_unit
          }}</b-td>
        </b-tr>
      </b-tbody>
    </b-table-simple>
  </div>
</template>

<script>
import _ from "lodash";

export default {
  name: "App",
  components: {},
  data() {
    return {
      invoice: [
        {
          id: "123",
          billing_sku_id: "FOOD_ITEMS",
          billing_sku_name: "Rice",
          total_units: 1,
          billing_sku_category: "Food Items",
          price_per_unit: 3,
        },
        {
          id: "456",
          billing_sku_id: "FOOD_ITEMS",
          billing_sku_name: "Wheat",
          total_units: 3,
          billing_sku_category: "Food Items",
          price_per_unit: 5,
        },
        {
          id: "789",
          billing_sku_id: "ELECTRICITY_ITEMS",
          billing_sku_name: "Bulb",
          total_units: 5,
          billing_sku_category: "Electricity Items",
          price_per_unit: 50,
        },
      ],
    };
  },
  computed: {
    goodsGroupedByCategory() {
      return _.groupBy(this.invoice, "billing_sku_category");
    },
  },
  methods: {
    exportTable() {
      console.log("hello");
    },
  },
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  padding: 10px;
}
</style>

Upvotes: 5

Views: 8764

Answers (2)

hamid-davodi
hamid-davodi

Reputation: 1966

I found a solution with the help of vue-html2pdf package. First I created a separate component called TableCompo and the code of it comes here:

TableCompo.vue:

<template>
  <div id="tableMe">
    <b-table-simple outlined id="htmltable">
      <b-thead class="b-table__head">
        <b-tr>
          <b-th class="small-tab">Goods</b-th>
          <b-th>Units</b-th>
          <b-th>Price Per Unit</b-th>
          <b-th>Total Price</b-th>
        </b-tr>
      </b-thead>
      <b-tbody v-for="(service, index) in goodsGroupedByCategory" :key="index">
        <b-tr class="category-line">
          <b-th class="small-tab cs-textstyle-paragraph-small-bold">{{
              index
            }}</b-th>
          <b-td></b-td>
          <b-td></b-td>
          <b-th class="cs-textstyle-paragraph-small-bold">{{
              service.reduce(function (prev, curr) {
                return prev + curr.total_units * curr.price_per_unit;
              }, 0)
            }}</b-th>
        </b-tr>
        <b-tr
            v-for="serviceItem in service"
            :key="serviceItem.id"
            class="item-line"
        >
          <b-td class="big-tab cs-textstyle-paragraph-small">{{
              serviceItem.billing_sku_name
            }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
              serviceItem.total_units
            }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
              serviceItem.price_per_unit
            }}</b-td>
          <b-td class="cs-textstyle-paragraph-small">{{
              serviceItem.total_units * serviceItem.price_per_unit
            }}</b-td>
        </b-tr>
      </b-tbody>
    </b-table-simple>
  </div>
</template>

<script>
import _ from "lodash";

export default {
  name: "TableCompo",
  data() {
    return {
      invoice: [
        {
          id: "123",
          billing_sku_id: "FOOD_ITEMS",
          billing_sku_name: "Rice",
          total_units: 1,
          billing_sku_category: "Food Items",
          price_per_unit: 3,
        },
        {
          id: "456",
          billing_sku_id: "FOOD_ITEMS",
          billing_sku_name: "Wheat",
          total_units: 3,
          billing_sku_category: "Food Items",
          price_per_unit: 5,
        },
        {
          id: "789",
          billing_sku_id: "ELECTRICITY_ITEMS",
          billing_sku_name: "Bulb",
          total_units: 5,
          billing_sku_category: "Electricity Items",
          price_per_unit: 50,
        },
      ],
    };
  },
  computed: {
    goodsGroupedByCategory() {
      return _.groupBy(this.invoice, "billing_sku_category");
    },
  },
}
</script>

<style scoped>
#tableMe {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  padding: 10px;
}
</style>

After that I created a parent component (or a view) that using this component and vue-html2pdf package to export the content of table as pdf:

TableView.vue:

<template>
  <div>
    <b-button @click="generateReport" class="mb-3">Export</b-button>
    <!-- first usage of table component: this is for showing the table in browser for users -->
    <table-compo></table-compo>

    <vue-html2pdf
        :show-layout="false"
        :float-layout="true"
        :enable-download="true"
        :preview-modal="false"
        :paginate-elements-by-height="1400"
        filename="my-table"
        :pdf-quality="2"
        :manual-pagination="false"
        pdf-format="a5"
        pdf-orientation="landscape"
        pdf-content-width="100%"
        ref="html2Pdf"
    >
      <section slot="pdf-content">
      <!-- second usage of table component: this is for putting the contents of table to final pdf  -->
        <table-compo></table-compo>
      </section>
    </vue-html2pdf>
  </div>
</template>

<script>
import VueHtml2pdf from 'vue-html2pdf';
import TableCompo from '../components/TableCompo'
export default {
  name: "TableView",
  components: {
    VueHtml2pdf,
    TableCompo
  },
  methods: {
    /*
        Generate Report using refs and calling the
        refs function generatePdf()
    */
    generateReport () {
      this.$refs.html2Pdf.generatePdf();
    }
  },
}
</script>

<style scoped>

</style>

If you are not happy with my settings, see the documentation of that package to find your desired settings.

Upvotes: 3

ottosatto
ottosatto

Reputation: 601

You have this package: https://www.npmjs.com/package/xlsx In your html, create a button and with the @click="exportInvoiceButton()". That's one of the way you can do it in Frontend, but, alternatively, and probably the best way to do this export is from the backend, so you can have more flexibility of what to export.

import XLSX from 'xlsx';    
//...
methods: {
        //...
        exportInvoiceButton() {
            const invoices = this.invoices.reduce((ac, invoice) => { 
                ac.push({ 
                    billing_sku_id: invoice.billing_sku_id, 
                    billing_sku_name: invoice.billing_sku_name,
                    total_units: invoice.total_units,
                    // ...
                }); 
                return ac;
            }, [])
    
            var invoicesWS = XLSX.utils.json_to_sheet(invoices)
    
            // A workbook is the name given to an Excel file
            var wb = XLSX.utils.book_new() // make Workbook of Excel
    
            // add Worksheet to Workbook
            // Workbook contains one or more worksheets
            XLSX.utils.book_append_sheet(wb, invoicesWS, 'Invoices list') // invoices list is name of Worksheet
    
    
            // export Excel file
            XLSX.writeFile(wb, 'Invoices.xlsx')
    
        }
        //...
    }

Upvotes: 4

Related Questions