Skip to content

Instantly share code, notes, and snippets.

@bayareawebpro
Last active November 3, 2019 22:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bayareawebpro/2f83ffb553df9f2a8b0396cbc4d26f7d to your computer and use it in GitHub Desktop.
Save bayareawebpro/2f83ffb553df9f2a8b0396cbc4d26f7d to your computer and use it in GitHub Desktop.

LaravelMicro.js Repository

Implement A DataTable using the repository.

Blade Example:

<v-table
    ref="tasks"
    route="tasks/table">
    <template slot="caption">
        <i class="fa fa-tasks"></i> Tasks
    </template>
    <template slot="thead" slot-scope="table">
        <th class="text-center" style="width: 60px">ID</th>
        <th class="text-left" style="width: auto">Script</th>
        <th class="text-left" style="width: 160px">Status</th>
        <th class="text-left">Timestamp</th>
        <th class="text-left">Edit</th>
    </template>
    <template slot="row" slot-scope="row">
        <th class="text-center">@{{ row.data.id }}</th>
        <td class="text-left">@{{ row.data.name }}</td>
        <td class="text-left">@{{ row.data.statusLabel }}</td>
        <td class="text-left">@{{ row.data.created_at }}</td>
        <td class="text-left">
            <a :href="`/tasks/${row.data.id}`" class="btn btn-sm">
                <i class="fa fa-edit"></i> Show
            </a>
        </td>
    </template>
</v-table>

Component Example:

<script>
    import {Repository} from 'laravel-micro.js'

    export default {
        name: "Table",
        props: {
            route: {
                type: String,
                required: true,
            }
        },
        data() {
            return {
                table: new Repository,
                isLoading: false,
                isLoaded: false,
                search: '',
            }
        },
        computed: {
            rows() {
                return this.table.get('data', [])
            },
            params() {
                return {
                    search: this.search,
                    page: this.currentPage,
                    orderBy: this.orderedBy,
                    sort: this.sortedBy,
                }
            },
            isFirstPage() {
                return this.currentPage === 1
            },
            isLastPage() {
                return this.currentPage === this.lastPage
            },
            sortedBy: {
                get() {
                    return this.table.get('sort', 'desc')
                },
                set(val) {
                    this.table.set('sort', val)
                    this.fetch()
                }
            },
            orderedBy: {
                get() {
                    return this.table.get('orderBy', 'id')
                },
                set(val) {
                    this.table.set('orderBy', val)
                }
            },
            currentPage: {
                get() {
                    return this.table.get('current_page', 1)
                },
                set(val) {
                    this.table.set('current_page', val)
                }
            },
            lastPage() {
                return this.table.get('last_page', 1)
            },
        },
        methods: {
            sort(val) {
                if (!this.isSortedBy(val)) {
                    this.isLoading = val
                    this.sortedBy = val
                    this.fetch()
                }
            },
            isSortedBy(val) {
                return this.sortedBy === val
            },
            order(val) {
                if (!this.isSortedBy(val)) {
                    this.isLoading = val
                    this.orderedBy = val
                    this.fetch()
                }
            },
            isOrderedBy(val) {
                return this.orderedBy === val
            },
            nextPage() {
                if (this.currentPage < this.table.get('last_page', 1)) {
                    this.isLoading = 'next'
                    this.currentPage++
                    this.fetch()
                }
            },
            prevPage() {
                if (this.currentPage > 1) {
                    this.isLoading = 'prev'
                    this.currentPage--
                    this.fetch()
                }
            },
            fetchSearch(){
                this.isLoading = 'search'
                this.currentPage = 1
                this.fetch()
            },
            async fetch() {
                await this.$options.$http
                    .get(this.route, {
                        params: this.params
                    }).then(({data}) => {
                        this.table.update(data)
                        this.isLoaded = true
                    }).finally(() => {
                        this.isLoading = false
                    })
            },
            hasSlot(name) {
                return !!this.$slots[name]
            }
        },
        created() {
            this.$options.$http = this.$app.make('Http')
            this.fetch()
        }
    }
</script>
<template>
    <div>
        <div class="flex flex-wrap">
            <div class="mr-1 flex flex-row">
                <input
                    type="text"
                    class="search"
                    v-model="search"
                    @keydown.enter="fetchSearch"
                    placeholder="Search...">
                <button
                    type="button"
                    @click="fetchSearch"
                    class="btn btn-search">
                    <v-loading
                        :size="20"
                        color="white"
                        v-if="isLoading === 'search'">
                    </v-loading>
                    <i v-else class="fa fa-search"></i>
                </button>
            </div>
            <button
                class="btn btn-sm"
                @click.prevent="sort('asc')"
                :disabled="isSortedBy('asc')">
                <v-loading
                    :size="12"
                    color="white"
                    v-if="isLoading === 'asc'">
                </v-loading>
                <span v-else>Asc</span>
            </button>
            <div class="ml-1"></div>
            <button
                class="btn btn-sm"
                @click.prevent="sort('desc')"
                :disabled="isSortedBy('desc')">
                <v-loading :size="12" color="white" v-if="isLoading === 'desc'"></v-loading>
                <span v-else>Desc</span>
            </button>
            <slot
                name="filters"
                :sort="sort"
                :table="table"
                :nextPage="nextPage"
                :prevPage="prevPage"
                :isSortedBy="isSortedBy"
                :isOrderedBy="isOrderedBy"
                :isFirstPage="isFirstPage"
                :isLastPage="isLastPage">
            </slot>
            <div class="flex flex-grow"></div>
            <div class="text-gray-400 text-sm self-center">
                Page {{ currentPage}} of {{lastPage}}
            </div>
        </div>
        <div class="card shadow-xl my-3">
            <div class="card-header">
                <slot name="caption"></slot>
            </div>
            <div class=" overflow-x-auto overflow-y-hidden">

                <table class="table">
                    <thead>
                    <tr>
                        <slot
                            name="thead"
                            :sort="sort"
                            :table="table"
                            :nextPage="nextPage"
                            :prevPage="prevPage"
                            :isSortedBy="isSortedBy"
                            :isOrderedBy="isOrderedBy"
                            :isFirstPage="isFirstPage"
                            :isLastPage="isLastPage">
                        </slot>
                    </tr>
                    </thead>
                    <tbody v-if="rows.length">
                    <tr v-for="row in rows">
                        <slot
                            name="row"
                            :data="row"
                            :sort="sort"
                            :table="table"
                            :nextPage="nextPage"
                            :prevPage="prevPage"
                            :isSortedBy="isSortedBy"
                            :isOrderedBy="isOrderedBy"
                            :isFirstPage="isFirstPage"
                            :isLastPage="isLastPage">
                        </slot>
                    </tr>
                    </tbody>
                    <tbody v-else-if="isLoaded">
                    <tr>
                        <td colspan="100%">
                            <div class="alert info">No results.</div>
                        </td>
                    </tr>
                    </tbody>
                    <tfoot v-if="hasSlot('footer')">
                    <tr>
                        <slot
                            name="tfoot"
                            :sort="sort"
                            :table="table"
                            :nextPage="nextPage"
                            :prevPage="prevPage"
                            :isSortedBy="isSortedBy"
                            :isOrderedBy="isOrderedBy"
                            :isFirstPage="isFirstPage"
                            :isLastPage="isLastPage">
                        </slot>
                    </tr>
                    </tfoot>
                </table>
            </div>
        </div>
        <div class="flex flex-wrap">
            <button
                class="btn"
                :disabled="isFirstPage"
                @click.prevent="prevPage">
                <v-loading
                    :size="14"
                    color="white"
                    v-if="isLoading === 'prev'">
                </v-loading>
                <span v-else><i class="fa fa-chevron-left"></i> Prev</span>
            </button>
            <div class="ml-1"></div>
            <button
                class="btn"
                :disabled="isLastPage"
                @click.prevent="nextPage">
                <v-loading
                    :size="14"
                    color="white"
                    v-if="isLoading === 'next'">
                </v-loading>
                <span v-else>Next <i class="fa fa-chevron-right"></i></span>
            </button>
            <div class="flex flex-grow"></div>
            <div class="text-gray-400 text-sm self-center">
                Page {{ currentPage}} of {{lastPage}}
            </div>
        </div>
    </div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment