Skip to content

Instantly share code, notes, and snippets.

@ais-one
Last active March 14, 2019 23:25
Show Gist options
  • Save ais-one/723527481566645ab33b36a933632558 to your computer and use it in GitHub Desktop.
Save ais-one/723527481566645ab33b36a933632558 to your computer and use it in GitHub Desktop.
vue-crud-x - Book.vue
<template>
<div id="not-needed">
<v-layout row wrap>
<v-flex xs12>
<vue-crud-x ref="book-table" storeName="book-table" :parentId="null" v-bind="bookDefs" @form-open="openBookForm">
<template slot="filter" slot-scope="{ filterData, parentId, storeName }">
<h1>Custom {{ storeName }} Filter Slot</h1>
<div v-for="(filter, index) in filterData" :key="index">
<component :is="filter.type" v-model="filter.value" v-bind="filter.attrs"></component>
</div>
</template>
<!-- <template slot="table" slot-scope="{ records, totalRecs, pagination }">
<div v-for="record in records" :key="record.id"><p>{{ record.id }} {{ record.name }} <v-btn @click="$refs['book-table'].crudFormOpen(record.id)">Open</v-btn></p></div>
<div>{{ totalRecs }} {{ pagination }}</div>
</template> -->
<template slot="form" slot-scope="{ record, parentId, storeName }">
<div>
<h1>Custom {{ storeName }} Form Slot - Has Parent: {{ !!parentId }}</h1>
<v-card-text>
<v-text-field label="Name" v-model="record.name"></v-text-field>
<v-select label="Category" v-model="record.categoryId" :items="categories" required item-text="name" item-value="id"></v-select>
<v-autocomplete multiple v-model="authorIds" :items="items" :loading="isLoading" :search-input.sync="search"
chips clearable hide-selected item-text="name" item-value="id" label="Search for a author... (Maximum 2)"
>
<template slot="no-data">
<v-list-tile>
<v-list-tile-title>No author yet...</v-list-tile-title>
</v-list-tile>
</template>
<template slot="selection" slot-scope="{ item, selected }">
<v-chip :selected="selected" close @input="remove(item)">
<span v-text="item.name"></span>
</v-chip>
</template>
<template slot="item" slot-scope="{ item }">
<v-list-tile-content>
<v-list-tile-title v-text="item.name"></v-list-tile-title>
</v-list-tile-content>
</template>
</v-autocomplete>
<v-btn @click.stop.prevent="gotoPages(record.id)" dark>View Book Pages</v-btn>
</v-card-text>
</div>
</template>
</vue-crud-x>
</v-flex>
</v-layout>
</div>
</template>
<script>
import { from } from 'rxjs'
import { pluck, filter, debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators' // map
import { http } from '@/axios'
import VueCrudX from '@/VueCrudX'
export default {
subscriptions () {
return {
// clean autocomplete using rxJS
items: this.$watchAsObservable('search').pipe(
pluck('newValue'), filter(text => text ? text.length > 2 : false),
debounceTime(500), distinctUntilChanged(), switchMap(this.fetchTerm)
)
}
},
name: 'book',
components: { VueCrudX },
data () {
return {
// for autocomplete
isLoading: false, authorIds: [], search: '',
// list of categories - can be moved to database in future
categories: [ { id: 1, name: 'cat1' }, { id: 2, name: 'cat2' } ],
// props to be passed into vue-crud-x component
bookDefs: {
crudTable: {
confirmCreate: true, confirmUpdate: true, confirmDelete: true,
headers: [
{ text: 'Book Name', value: 'name', class: 'pa-1' },
{ text: 'Category', value: 'categoryName', class: 'pa-1' }
],
formatters: (value, _type) => value, // format table cell data
doPage: true // do pagination?
},
crudFilter: {
FilterVue: null,
filterData: {
name: { // search filter by Book table property called 'name'
type: 'v-text-field', value: '', attrs: { label: 'Book Name' }
}
}
},
crudForm: {
FormVue: () => {},
formAutoData: null,
defaultRec: () => ({
id: '', name: '', categoryId: '', categoryName: '', authorIds: [], authors: []
})
},
crudOps: { // CRUD
export: async (payload) => { },
find: async (payload) => {
let records = []
const { pagination, filterData } = payload // pagination: { sortBy, descending }
const { page, rowsPerPage } = pagination
let params = { page: page > 0 ? page - 1 : 0, limit: rowsPerPage } // set query params
params.name = filterData.name.value
try {
const { data: { results, total } } = await http.get('/api/books', { params })
results.forEach(row => { records.push(row) })
pagination.totalItems = total
} catch (e) { }
return { records, pagination }
},
findOne: async (payload) => {
const { id } = payload
try {
const { data } = await http.get(`/api/books/${id}`)
return data
} catch (e) { }
return { }
},
create: async (payload) => {
try {
let { record: { id, ...noIdData } } = payload
const rv = await http.post('/api/authors', noIdData)
} catch (e) { return 500 }
return 201
},
update: async (payload) => {
try {
let { record: { id, name, categoryId, authorIds } } = payload // authorIds
const rv = await http.patch(`/api/books/${id}`, { name, categoryId, authorIds })
} catch (e) { return 500 }
return 200
},
delete: null // not implemented
}
}
}
},
watch: {
authorIds (val) {
if (val.length > 2) val.pop()
if (this.$refs['book-table']) this.$refs['book-table'].record.authorIds = val
}
},
methods: {
gotoPages (id) { // go to pages table for selected book
this.$router.push({ path: `/books/${id}/pages` })
},
remove (item) {
const index = this.authorIds.indexOf(item.id)
if (index >= 0) this.authorIds.splice(index, 1)
},
openBookForm (item) {
this.authorIds = item.authorIds
this.items = item.authors
},
fetchTerm (term) {
return from(
http.get('/api/authors', { params: { page: 0, limit: 20, search: term } }).then(res => res.data.results)
)
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment