mirror of
https://github.com/frappe/books.git
synced 2024-11-13 00:46:28 +00:00
Form
- Add Submit Buttons - Disable inputs in submitted form - Simplify FormLayout template
This commit is contained in:
parent
8f2c48c3df
commit
ea441c240b
@ -4,6 +4,8 @@
|
||||
v-if="shouldRenderForm"
|
||||
:doc="doc"
|
||||
@save="save"
|
||||
@submit="submit"
|
||||
@revert="revert"
|
||||
/>
|
||||
<div class="p-3">
|
||||
<form-layout
|
||||
@ -89,6 +91,16 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
async submit() {
|
||||
this.doc.set('submitted', 1);
|
||||
await this.save();
|
||||
},
|
||||
|
||||
async revert() {
|
||||
this.doc.set('submitted', 0);
|
||||
await this.save();
|
||||
},
|
||||
|
||||
onValidate(fieldname, isValid) {
|
||||
if (!isValid && !this.invalidFields.includes(fieldname)) {
|
||||
this.invalidFields.push(fieldname);
|
||||
|
@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div class="frappe-form-actions d-flex justify-content-between align-items-center p-3 border-bottom">
|
||||
<h5 class="m-0">{{ title }}</h5>
|
||||
<f-button primary :disabled="!isDirty" @click="$emit('save')">{{ _('Save') }}</f-button>
|
||||
<f-button primary v-if="isDirty" @click="$emit('save')">{{ _('Save') }}</f-button>
|
||||
<f-button primary v-if="showSubmit" @click="$emit('submit')">{{ _('Submit') }}</f-button>
|
||||
<f-button secondary v-if="showRevert" @click="$emit('revert')">{{ _('Revert') }}</f-button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -11,13 +13,32 @@ export default {
|
||||
props: ['doc'],
|
||||
data() {
|
||||
return {
|
||||
isDirty: false
|
||||
isDirty: false,
|
||||
showSubmit: false,
|
||||
showRevert: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.doc.on('change', () => {
|
||||
this.isDirty = this.doc._dirty;
|
||||
this.updateShowSubmittable();
|
||||
});
|
||||
this.updateShowSubmittable();
|
||||
},
|
||||
methods: {
|
||||
updateShowSubmittable() {
|
||||
this.showSubmit =
|
||||
this.meta.isSubmittable
|
||||
&& !this.isDirty
|
||||
&& !this.doc._notInserted
|
||||
&& this.doc.submitted === 0;
|
||||
|
||||
this.showRevert =
|
||||
this.meta.isSubmittable
|
||||
&& !this.isDirty
|
||||
&& !this.doc._notInserted
|
||||
&& this.doc.submitted === 1;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
meta() {
|
||||
|
@ -11,20 +11,11 @@
|
||||
:key="fieldname"
|
||||
:docfield="getDocField(fieldname)"
|
||||
:value="$data[fieldname]"
|
||||
:doc="doc"
|
||||
@change="value => updateDoc(fieldname, value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!layout">
|
||||
<frappe-control
|
||||
v-for="docfield in fields"
|
||||
v-if="shouldRenderField(docfield.fieldname)"
|
||||
:key="docfield.fieldname"
|
||||
:docfield="docfield"
|
||||
:value="$data[docfield.fieldname]"
|
||||
@change="value => updateDoc(docfield.fieldname, value)"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
@ -85,17 +76,21 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
layoutConfig() {
|
||||
if (!this.layout) return false;
|
||||
let layout = this.layout;
|
||||
|
||||
let config = this.layout;
|
||||
|
||||
if (Array.isArray(config)) {
|
||||
config = {
|
||||
sections: config
|
||||
}
|
||||
if (!layout) {
|
||||
const fields = this.fields.map(df => df.fieldname);
|
||||
layout = [{
|
||||
columns: [{ fields }]
|
||||
}];
|
||||
}
|
||||
|
||||
return config;
|
||||
if (Array.isArray(layout)) {
|
||||
layout = {
|
||||
sections: layout
|
||||
}
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="wrapper" class="datatable-wrapper"></div>
|
||||
<div class="table-actions mt-1">
|
||||
<div class="table-actions mt-1" v-if="!disabled">
|
||||
<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>
|
||||
</div>
|
||||
@ -16,7 +16,7 @@ import FrappeControl from './controls/FrappeControl';
|
||||
import { convertFieldsToDatatableColumns } from 'frappejs/client/ui/utils';
|
||||
|
||||
export default {
|
||||
props: ['doctype', 'rows'],
|
||||
props: ['doctype', 'rows', 'disabled'],
|
||||
data() {
|
||||
return {
|
||||
docs: this.getRowDocs(),
|
||||
@ -121,7 +121,12 @@ export default {
|
||||
},
|
||||
getColumns() {
|
||||
const fieldsToShow = this.meta.fields.filter(df => !df.hidden);
|
||||
return convertFieldsToDatatableColumns(fieldsToShow);
|
||||
const columns = convertFieldsToDatatableColumns(fieldsToShow);
|
||||
|
||||
if (this.disabled) {
|
||||
columns.forEach(col => col.editable = false);
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
addRow() {
|
||||
const doc = new Observable();
|
||||
|
@ -12,7 +12,8 @@ export default {
|
||||
onlyInput: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
computed: {
|
||||
id() {
|
||||
@ -71,7 +72,7 @@ export default {
|
||||
placeholder: '',
|
||||
value: this.value,
|
||||
required: this.docfield.required,
|
||||
disabled: this.docfield.disabled
|
||||
disabled: this.disabled
|
||||
}
|
||||
},
|
||||
getInputListeners() {
|
||||
|
@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<component
|
||||
:is="component"
|
||||
:docfield="docfield"
|
||||
:value="value"
|
||||
:onlyInput="onlyInput"
|
||||
@change="$emit('change', $event)"
|
||||
/>
|
||||
<component
|
||||
:is="component"
|
||||
:docfield="docfield"
|
||||
:value="value"
|
||||
:onlyInput="onlyInput"
|
||||
:disabled="isDisabled"
|
||||
@change="$emit('change', $event)"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import Base from './Base';
|
||||
@ -26,39 +27,52 @@ import Table from './Table';
|
||||
import Text from './Text';
|
||||
|
||||
export default {
|
||||
props: ['docfield', 'value', 'onlyInput'],
|
||||
computed: {
|
||||
component() {
|
||||
if (this.docfield.template) {
|
||||
// for controls with their own template
|
||||
// create a vue object for it
|
||||
return {
|
||||
extends: Base,
|
||||
render: null,
|
||||
template: this.docfield.template()
|
||||
}
|
||||
}
|
||||
props: ['docfield', 'value', 'onlyInput', 'doc'],
|
||||
computed: {
|
||||
component() {
|
||||
if (this.docfield.template) {
|
||||
// for controls with their own template
|
||||
// create a vue object for it
|
||||
return {
|
||||
extends: Base,
|
||||
render: null,
|
||||
template: this.docfield.template()
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
Autocomplete,
|
||||
Check,
|
||||
Code,
|
||||
Currency,
|
||||
Data,
|
||||
Date,
|
||||
DynamicLink,
|
||||
File,
|
||||
Float,
|
||||
Int,
|
||||
Link,
|
||||
Password,
|
||||
Select,
|
||||
Table,
|
||||
Text,
|
||||
}[this.docfield.fieldtype];
|
||||
}
|
||||
return {
|
||||
Autocomplete,
|
||||
Check,
|
||||
Code,
|
||||
Currency,
|
||||
Data,
|
||||
Date,
|
||||
DynamicLink,
|
||||
File,
|
||||
Float,
|
||||
Int,
|
||||
Link,
|
||||
Password,
|
||||
Select,
|
||||
Table,
|
||||
Text
|
||||
}[this.docfield.fieldtype];
|
||||
},
|
||||
isDisabled() {
|
||||
let disabled = this.docfield.disabled;
|
||||
|
||||
if (this.doc && this.doc.submitted) {
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
if (this.docfield.formula && this.docfield.fieldtype !== 'Table') {
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
return Boolean(disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.form-group {
|
||||
|
@ -3,6 +3,7 @@
|
||||
<model-table
|
||||
:doctype="docfield.childtype"
|
||||
:rows="value"
|
||||
:disabled="disabled"
|
||||
@update:rows="emitChange"
|
||||
/>
|
||||
</div>
|
||||
|
@ -10,7 +10,8 @@ export default {
|
||||
return {
|
||||
id: this.id,
|
||||
required: this.docfield.required,
|
||||
rows: 3
|
||||
rows: 3,
|
||||
disabled: this.disabled
|
||||
};
|
||||
},
|
||||
getDomProps() {
|
||||
|
Loading…
Reference in New Issue
Block a user