2018-06-27 14:38:27 +00:00
|
|
|
<template>
|
|
|
|
<div>
|
|
|
|
<div ref="wrapper" class="datatable-wrapper"></div>
|
2018-07-12 07:47:56 +00:00
|
|
|
<div class="table-actions mt-1" v-if="!disabled">
|
2018-07-09 12:59:51 +00:00
|
|
|
<f-button danger @click="removeCheckedRows" v-if="checkedRows.length">Remove</f-button>
|
|
|
|
<f-button light @click="addRow" v-if="!checkedRows.length">Add Row</f-button>
|
2018-06-27 14:38:27 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import Vue from 'vue';
|
|
|
|
import frappe from 'frappejs';
|
|
|
|
import Observable from 'frappejs/utils/observable';
|
|
|
|
import DataTable from 'frappe-datatable';
|
|
|
|
import FrappeControl from './controls/FrappeControl';
|
|
|
|
import { convertFieldsToDatatableColumns } from 'frappejs/client/ui/utils';
|
|
|
|
|
|
|
|
export default {
|
2018-07-12 07:47:56 +00:00
|
|
|
props: ['doctype', 'rows', 'disabled'],
|
2018-06-27 14:38:27 +00:00
|
|
|
data() {
|
|
|
|
return {
|
2018-07-09 12:59:51 +00:00
|
|
|
docs: this.getRowDocs(),
|
|
|
|
checkedRows: []
|
2018-06-27 14:38:27 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
meta() {
|
|
|
|
return frappe.getMeta(this.doctype);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.datatable = new DataTable(this.$refs.wrapper, {
|
|
|
|
columns: this.getColumns(),
|
|
|
|
data: this.docs,
|
|
|
|
layout: 'fluid',
|
|
|
|
checkboxColumn: true,
|
|
|
|
checkedRowStatus: false,
|
2018-07-09 12:59:51 +00:00
|
|
|
events: {
|
|
|
|
onCheckRow: () => {
|
|
|
|
this.checkedRows = this.datatable.rowmanager
|
|
|
|
.getCheckedRows()
|
|
|
|
.map(i => parseInt(i, 10));
|
|
|
|
}
|
|
|
|
},
|
2018-06-27 14:38:27 +00:00
|
|
|
getEditor: (colIndex, rowIndex, value, parent) => {
|
|
|
|
|
|
|
|
let inputComponent = null;
|
|
|
|
const docfield = this.datatable.getColumn(colIndex).field;
|
|
|
|
|
|
|
|
const fieldWrapper = document.createElement('div');
|
|
|
|
parent.appendChild(fieldWrapper);
|
|
|
|
|
|
|
|
const updateData = (fieldname, value) => {
|
|
|
|
const docs = this.datatable.datamanager.data;
|
|
|
|
const doc = docs[rowIndex];
|
|
|
|
doc.set(fieldname, value);
|
|
|
|
this.emitChange(doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
initValue() {
|
|
|
|
inputComponent = new Vue({
|
|
|
|
el: fieldWrapper,
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
docfield,
|
|
|
|
value
|
|
|
|
}
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
FrappeControl
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.$el.focus();
|
|
|
|
},
|
|
|
|
template: `<frappe-control
|
|
|
|
:docfield="docfield"
|
|
|
|
:value="value"
|
|
|
|
@change="value => updateValue(docfield.fieldname, value)"
|
|
|
|
:onlyInput="true"
|
|
|
|
/>`,
|
|
|
|
methods: {
|
|
|
|
updateValue(fieldname, value) {
|
|
|
|
this.value = value;
|
|
|
|
updateData(fieldname, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
setValue: (value, rowIndex, column) => {
|
|
|
|
inputComponent.value = value;
|
|
|
|
},
|
|
|
|
getValue: () => {
|
|
|
|
return inputComponent.$el.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
destroyed() {
|
|
|
|
this.datatable.destroy();
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
docs: function(newVal, oldVal) {
|
|
|
|
this.datatable.refresh(newVal);
|
|
|
|
},
|
|
|
|
rows: function(newVal, oldVal) {
|
|
|
|
this.docs = this.getRowDocs();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
getRowDocs() {
|
|
|
|
return (this.rows || []).map((row, i) => {
|
|
|
|
const doc = new Observable();
|
|
|
|
doc.set('idx', i);
|
|
|
|
for (let fieldname in row) {
|
|
|
|
doc.set(fieldname, row[fieldname]);
|
|
|
|
}
|
|
|
|
return doc;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
getColumns() {
|
2018-07-09 12:59:51 +00:00
|
|
|
const fieldsToShow = this.meta.fields.filter(df => !df.hidden);
|
2018-07-12 07:47:56 +00:00
|
|
|
const columns = convertFieldsToDatatableColumns(fieldsToShow);
|
|
|
|
|
|
|
|
if (this.disabled) {
|
|
|
|
columns.forEach(col => col.editable = false);
|
|
|
|
}
|
|
|
|
return columns;
|
2018-06-27 14:38:27 +00:00
|
|
|
},
|
|
|
|
addRow() {
|
|
|
|
const doc = new Observable();
|
|
|
|
doc.set('idx', this.docs.length);
|
|
|
|
this.docs.push(doc);
|
|
|
|
},
|
2018-07-09 12:59:51 +00:00
|
|
|
removeCheckedRows() {
|
|
|
|
this.removeRows(this.checkedRows);
|
|
|
|
this.checkedRows = [];
|
|
|
|
this.datatable.rowmanager.checkAll(false);
|
|
|
|
},
|
|
|
|
removeRows(indices) {
|
|
|
|
// convert to array
|
|
|
|
if (!Array.isArray(indices)) {
|
|
|
|
indices = [indices];
|
|
|
|
}
|
|
|
|
// convert string to number
|
|
|
|
indices = indices.map(i => parseInt(i, 10));
|
|
|
|
// filter
|
|
|
|
this.docs = this.docs.filter(doc => !indices.includes(parseInt(doc.idx, 10)));
|
|
|
|
// recalculate idx
|
|
|
|
this.docs.forEach((doc, i) => {
|
|
|
|
doc.set('idx', i);
|
|
|
|
});
|
|
|
|
},
|
2018-06-27 14:38:27 +00:00
|
|
|
emitChange(doc) {
|
|
|
|
this.$emit('update:rows', this.docs, doc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss">
|
2018-07-06 08:48:26 +00:00
|
|
|
@import "frappe-datatable/dist/frappe-datatable.css";
|
2018-06-27 14:38:27 +00:00
|
|
|
|
|
|
|
.datatable-wrapper {
|
|
|
|
.form-control {
|
|
|
|
border: none;
|
|
|
|
box-shadow: none;
|
|
|
|
height: 100%;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|