2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 03:29:00 +00:00

Add Table control with ModelTable

- onlyInput prop for FrappeControl
This commit is contained in:
Faris Ansari 2018-06-07 07:23:26 +05:30
parent 577ee9d21d
commit a268e1a4ef
10 changed files with 239 additions and 45 deletions

View File

@ -37,6 +37,7 @@ module.exports = {
label: 'Schedule'
}
],
titleField: 'title',
keywordFields: [],
isSingle: 0,
listSettings: {

View File

@ -25,8 +25,10 @@
"dependencies": {
"bootstrap": "^4.1.1",
"feather-icons": "^4.7.3",
"frappe-datatable": "^0.0.9",
"frappejs": "^0.0.7",
"vue": "^2.5.2",
"vue-flatpickr-component": "^7.0.2",
"vue-router": "^3.0.1"
},
"devDependencies": {

View File

@ -1,5 +1,4 @@
<template>
<keep-alive>
<div class="frappe-form">
<form-actions
v-if="shouldRenderForm"
@ -11,11 +10,9 @@
:doc="doc"
:fields="meta.fields"
:layout="meta.layout"
@field-change="updateDoc"
/>
<not-found v-if="notFound" />
</div>
</keep-alive>
</template>
<script>
import frappe from 'frappejs';
@ -31,7 +28,7 @@ export default {
},
data() {
return {
doc: null,
docLoaded: false,
notFound: false,
invalid: false
}
@ -41,13 +38,14 @@ export default {
return frappe.getMeta(this.doctype);
},
shouldRenderForm() {
return this.name && this.doc;
return this.name && this.docLoaded;
}
},
async created() {
if (!this.name) return;
try {
this.doc = await frappe.getDoc(this.doctype, this.name);
this.docLoaded = true;
} catch(e) {
this.notFound = true;
}
@ -71,16 +69,10 @@ export default {
}
} catch (e) {
console.error(e);
// frappe.ui.showAlert({ message: frappe._('Failed'), color: 'red' });
return;
}
},
updateDoc(fieldname, value) {
this.$data[fieldname] = value;
this.doc.set(fieldname, value);
},
checkValidity() {
return true;
},

View File

@ -7,7 +7,7 @@
:key="fieldname"
:docfield="getDocField(fieldname)"
:value="$data[fieldname]"
@change="$emit('field-change', fieldname, $event)"
@change="value => updateDoc(docfield.fieldname, value)"
/>
</div>
</div>
@ -17,36 +17,51 @@
:key="docfield.fieldname"
:docfield="docfield"
:value="$data[docfield.fieldname]"
@change="$emit('field-change', docfield.fieldname, $event)"
@change="value => updateDoc(docfield.fieldname, value)"
/>
</div>
</form>
</template>
<script>
import FrappeControl from './controls/FrappeControl'
import FrappeControl from './controls/FrappeControl';
export default {
name: 'FormLayout',
props: ['doc', 'fields', 'layout'],
data() {
const dataObj = {};
for (let field of this.fields) {
dataObj[field.fieldname] = this.doc[field.fieldname];
}
return dataObj;
},
created() {
this.doc.on('change', ({ doc, fieldname }) => {
this[fieldname] = doc[fieldname];
});
},
methods: {
getDocField(fieldname) {
return this.fields.find(df => df.fieldname === fieldname);
}
},
components: {
FrappeControl
name: 'FormLayout',
props: ['doc', 'fields', 'layout'],
data() {
const dataObj = {};
for (let df of this.fields) {
dataObj[df.fieldname] = this.doc[df.fieldname];
if (df.fieldtype === 'Table' && !dataObj[df.fieldname]) {
dataObj[df.fieldname] = [];
}
}
}
return dataObj;
},
created() {
this.doc.on('change', ({ doc, fieldname }) => {
if (fieldname) {
// update value
this[fieldname] = doc[fieldname];
} else {
// update all values
this.fields.forEach(df => {
this[df.fieldname] = doc[df.fieldname];
});
}
});
},
methods: {
getDocField(fieldname) {
return this.fields.find(df => df.fieldname === fieldname);
},
updateDoc(fieldname, value) {
this.doc.set(fieldname, value);
}
},
components: {
FrappeControl
}
};
</script>

View File

@ -1,5 +1,4 @@
<template>
<keep-alive>
<div class="frappe-list">
<list-actions
:doctype="doctype"
@ -19,7 +18,6 @@
</list-item>
</ul>
</div>
</keep-alive>
</template>
<script>
import frappe from 'frappejs';
@ -61,7 +59,7 @@ export default {
async updateList() {
const data = await frappe.db.getAll({
doctype: this.doctype,
fields: ['name', ...this.meta.keywordFields]
fields: ['name', ...this.meta.keywordFields, this.meta.titleField]
});
this.data = data;
@ -71,9 +69,7 @@ export default {
this.$router.push(`/edit/${this.doctype}/${name}`);
},
async deleteCheckedItems() {
debugger
await frappe.db.deleteMany(this.doctype, this.checkList);
debugger
this.checkList = [];
},
toggleCheck(name) {

View File

@ -0,0 +1,138 @@
<template>
<div>
<div ref="wrapper" class="datatable-wrapper"></div>
<div class="table-actions mt-1">
<button type="button" @click="addRow" class="btn btn-sm btn-light border">Add Row</button>
</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 {
props: ['doctype', 'rows'],
data() {
return {
docs: this.getRowDocs()
}
},
computed: {
meta() {
return frappe.getMeta(this.doctype);
}
},
mounted() {
this.datatable = new DataTable(this.$refs.wrapper, {
columns: this.getColumns(),
data: this.docs,
layout: 'fluid',
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;
}
}
}
});
console.log(this.datatable)
},
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() {
return convertFieldsToDatatableColumns(this.meta.fields);
},
addRow() {
const doc = new Observable();
doc.set('idx', this.docs.length);
this.docs.push(doc);
},
emitChange(doc) {
this.$emit('update:rows', this.docs, doc);
}
}
}
</script>
<style lang="scss">
@import "frappe-datatable/dist/frappe-datatable.css";
.datatable-wrapper {
.form-control {
border: none;
box-shadow: none;
height: 100%;
padding: 0;
}
}
</style>

View File

@ -1,9 +1,19 @@
<script>
export default {
render(h) {
if (this.onlyInput) {
return this.getInputElement(h);
}
return this.getWrapperElement(h);
},
props: ['docfield', 'value'],
props: {
docfield: Object,
value: [String, Number, Array],
onlyInput: {
type: Boolean,
default: false
}
},
computed: {
id() {
return this.docfield.fieldname + '-'

View File

@ -1,5 +1,5 @@
<template>
<div class="form-group">
<div class="form-group" v-if="!onlyInput">
<label>{{ docfield.label }}</label>
<flat-pickr
:value="value"
@ -8,6 +8,13 @@
>
</flat-pickr>
</div>
<flat-pickr
v-else
:value="value"
class="form-control"
@on-change="emitChange"
>
</flat-pickr>
</template>
<script>
import flatPickr from 'vue-flatpickr-component';

View File

@ -1,5 +1,10 @@
<template>
<component :is="component" :docfield="docfield" :value="value" @change="$emit('change', $event)"/>
<component :is="component"
:docfield="docfield"
:value="value"
:onlyInput="onlyInput"
@change="$emit('change', $event)"
/>
</template>
<script>
import Autocomplete from './Autocomplete';
@ -11,10 +16,11 @@ import Date from './Date';
import Float from './Float';
import Link from './Link';
import Select from './Select';
import Table from './Table';
import Text from './Text';
export default {
props: ['docfield', 'value'],
props: ['docfield', 'value', 'onlyInput'],
computed: {
component() {
return {
@ -27,6 +33,7 @@ export default {
Float,
Link,
Select,
Table,
Text,
}[this.docfield.fieldtype];
}

View File

@ -0,0 +1,26 @@
<template>
<div class="form-group">
<model-table
:doctype="docfield.childtype"
:rows="value"
@update:rows="emitChange"
/>
</div>
</template>
<script>
import ModelTable from '../ModelTable';
import Base from './Base';
export default {
extends: Base,
components: {
ModelTable
},
methods: {
emitChange(rows, rowDoc) {
this.$emit('change', rows, rowDoc);
}
}
}
</script>