How to reinitialize DT after updating DOM

How to reinitialize DT after updating DOM

mimo_2005mimo_2005 Posts: 4Questions: 2Answers: 0

The DOM and datatable initialized correctly but when updating DOM with new record pushed to the main array "items" or when updating the DT destroyed but not initialized again

<DataTable id="tableId" :options="dt_options" class="display nowrap" width="100%">
                    <thead>
                        <tr>
                            <th class="text-uppercase text-secondary text-xs font-weight-bolder opacity-7">name</th>
                            <th class="no-sort text-secondary opacity-7">actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(branch, index) in items" :key="branch.id" >
                            <td>
                                <div class="d-flex px-2 py-1">
                                    <div class="d-flex flex-column justify-content-center">
                                        <h6 class="mb-0 text-sm" dir="ltr">{{branch.name}}</h6>
                                    </div>
                                </div>
                            </td>
                            <td>
                                <div class="align-content-start float-start" style="margin-left: 60px">
                                    <button type="button" class="btn-glass" @click.prevent="startUpdating(branch)">
                                        <font-awesome-icon icon="pen-to-square" style="color: orange" size="xl" data-toggle="tooltip" title="edit branch"/>
                                    </button>
                                </div>
                            </td>
                        </tr>
                    </tbody>
                </DataTable>
            </div>
        </div>
    </div>
</template>

<script>
import DataTable from "datatables.net-vue3";
export default {
    name: "Branches",
    props: ['branches'],
    components: {DataTable},
    created() {
        this.items = this.branches;
    },
    data() {
        return {
            items: [],
            editedItemIndex: null,
            dt_options: {
                select: false,
                responsive: true,
                lengthMenu: [5, 10, 25, 50],
                columnDefs: [
                    {
                        targets: 'no-sort',
                        orderable: false,
                    }
                ]
            }
        };
    },
    mounted() {
        this.freshDataTable();
    },
    beforeUpdate() {
        this.refreshDataTable();
    },
    methods: {
        push(newItem) {
            this.items.unshift(newItem);
        },
        update(newUpdatedItem) {
            if (this.editedItemIndex !== null) {
                this.items.splice(this.editedItemIndex, 1, newUpdatedItem);
                this.editedItemIndex = null;
            }
        },
        clean(index) {
            this.items.splice(index, 1);
        },
        freshDataTable() {
            this.$nextTick(() => {
                const table = $('#tableId');
                if (!$.fn.dataTable.isDataTable(table)) {
                    table.DataTable(this.dt_options);
                }
            });
        },
        destroyDataTable() {
            const table = $('#tableId');
            if ($.fn.dataTable.isDataTable(table)) {
                table.DataTable().clear();
                table.DataTable().destroy(true); // Pass true to remove the table from the DOM
            }
        },
        refreshDataTable() {
            this.destroyDataTable();
            this.freshDataTable();
        }
    }
};
</script>

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin

    Don't use v-for to populate the DataTable. It would mean that both Vue and DataTables are trying to control the same DOM element, which simply won't work.

    If you have a local array of data to want to show, you need to populate it using the data attribute - see the documentation here.

    I'll add a clear note to that page saying not to use v-for as there have been a number of posts with the same issue recently.

    Allan

  • mimo_2005mimo_2005 Posts: 4Questions: 2Answers: 0
    edited October 28

    I got it, and reformatted the component but I can't fire the call back function by the rendered button as following:

    data() {
            return {
                columns: [
                    {data: 'name'},
                    {
                        data: null,
                        orderable: false,
                        render: (data) => {
                            return `<button type="button" @click.prevent="startUpdating(${data})">update</button>`;
                        }
                    },
                ]
            }
        },
    
  • allanallan Posts: 63,489Questions: 1Answers: 10,470 Site admin
    Answer ✓

    You need to use a slot if you are planning to have the button interact with the rest of the document through events.

    Allan

  • mimo_2005mimo_2005 Posts: 4Questions: 2Answers: 0
    edited October 30

    @allan I'm trying to inject a component to the body of the table( without datatable with a normal table it works like expected but I don't know the trick to make it done in datatable):

    <template>
    <div class="card-body px-0 pt-0 pb-2">
                <div class="table-responsive p-0">
                    <DataTable :columns="columns" :data="items" :options="dt_options" ref="table" class="display stripe" width="100%">
                        <template v-slot:row="{ data }">
                            <user :user="data" @edit-user="(payload) => startUpdating(payload)"></user>
                        </template>
                    </DataTable>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
    import User from "../Childs/User.vue";
    import collection from "../../mixins/Collection.js";
    import AddEditUser from "../Main/AddEditUser.vue";
    export default {
        name: "Users",
        mixins: [collection],
        props: ['users', 'roles'],
        components: {FontAwesomeIcon, User, AddEditUser},
        created() {
            this.items = this.users;
        },
        data() {
            return {
                columns: [
                    { data: 'name', title: 'phone' },
                    { data: 'name', title: 'role' },
                    { data: 'name', title: 'status' },
                    { data: 'name', title: 'depend. No' },
                    { data: null, orderable: false, title: 'actions'},
                ],
            };
        },
        methods: {
            startUpdating(user) {
                this.editedItemIndex = this.items.findIndex(x => x.id === user.id);
                this.emitter.emit('edit_user', {user});
            },
            startAdding () {
                this.emitter.emit('add_user');
            }
        }
    
    }
    </script>
    
Sign In or Register to comment.