<!–
Vuetify component structure inspired by CRUD example from official docs: https://vuetifyjs.com/components/data-tables
–>
<template>
<div> <v-toolbar flat color="white"> <v-toolbar-title><%= plural_name.capitalize %></v-toolbar-title> <v-spacer /> <v-dialog v-model="dialog" max-width="500px"> <v-btn slot="activator" color="primary" dark class="mb-2">New Item</v-btn> <v-card> <v-card-title> <span class="headline">{{ formTitle }}</span> </v-card-title> <v-card-text> <v-container grid-list-md> <v-layout wrap> <div v-if="editedId !== -1"> <%= primary_key_name.capitalize %> {{editedItem.<%= primary_key_name %>}} </div> <%= attributes_names_without_id.map { |name| (<<-JS).strip }.join("\n#{' ' * 26}") <v-flex xs12 sm12 md12> <v-text-field v-model="editedItem.#{name}" label="#{name.capitalize}" /> </v-flex> JS %> </v-layout> </v-container> </v-card-text> <v-card-actions> <v-spacer></v-spacer> <v-btn color="blue darken-1" flat @click.native="close">Cancel</v-btn> <v-btn color="blue darken-1" flat @click.native="save">Save</v-btn> </v-card-actions> </v-card> </v-dialog> </v-toolbar> <v-data-table :headers="headers" :items="items" hide-actions class="elevation-1" > <template slot="items" slot-scope="props"> <%= attributes_names.map { |name| "<td>{{ props.item.#{name} }}</td>" }.join("\n#{' ' * 10}") %> <td> <v-icon small class="mr-2" @click="editItem(props.item)" > edit </v-icon> <v-icon small @click="deleteItem(props.item)" > delete </v-icon> </td> </template> </v-data-table> <v-snackbar v-model="errorSnackbar" top color="error" :timeout="6000"> Error occured{{renderErrorText}} </v-snackbar> </div>
</template>
<script>
import axios from 'axios' const routeURL = '<%= route_url %>'; export default { methods: { resetToDefault() { this.editedId = -1; Object.assign(this.editedItem, this.defaultItem); }, close() { this.resetToDefault(); this.dialog = false; }, errorHandler(error) { if (error.response) { const data = error.response.data; this.errorText = data.errors || data; } this.errorSnackbar = true; }, save() { if (this.editedId === -1) { axios.post(routeURL, this.editedItem).then(res => { this.items.push(res.data); this.close(); }).catch(this.errorHandler.bind(this)); } else { axios.patch(routeURL + '/' + this.editedId, this.editedItem).then(res => {; var elementIndex = this.findItemById(res.data.<%= primary_key_name %>); if (elementIndex !== -1) { Object.assign(this.items[elementIndex], res.data); } this.close(); }).catch(this.errorHandler.bind(this)); } }, findItemById(id) { return this.items.findIndex(element => { return element.<%= primary_key_name %> == id; }); }, editItem(item) { this.editedId = item.<%= primary_key_name %>; Object.assign(this.editedItem, item); this.dialog = true; }, deleteItem(item) { const id = item.<%= primary_key_name %>; const run = confirm( 'Are you sure you want to delete <%= singular_name %> with <%= primary_key_name %> ' + id + '?' ); if (run) { axios.delete(routeURL + '/' + id).then(res => { const index = this.findItemById(id); if (index !== -1) { this.items.splice(index, 1); } }).catch(this.errorHandler.bind(this)); } } }, computed: { renderErrorText() { return this.errorText ? ': ' + this.errorText : ''; }, formTitle () { return this.editedId === -1 ? 'New Item' : 'Edit Item'; } }, created() { this.resetToDefault(); axios.get(routeURL).then(res => { this.items = res.data; }).catch(this.errorHandler.bind(this)); }, data() { return { defaultItem: { // you can add default values for your attributes here <%= render_attributes_defaults(10) %> }, editedItem: { <%= render_attributes_defaults(10) %> }, editedId: -1, errorSnackbar: false, errorText: null, dialog: false, items: [], headers: [ <%= attributes_names.map {|name| (<<-JS).strip }.join(",\n#{' ' * 10}") { text: '#{name.capitalize}', value: '#{name}' } JS %> ] }; } };
</script>