UNPKG

4.9 kBPlain TextView Raw
1<script>
2import Vue from 'vue';
3import clone from 'clone';
4import { VForm, VContainer } from 'vuetify/lib/components';
5import types from './types';
6import propsResolver from './propsResolver';
7import { buildComponentsTree, renderComponentsTree } from './utils';
8
9function getFields(node) {
10 return node.fields ? node.fields.map((field) => getFields(field)) : node;
11}
12
13export default {
14 name: 'VuetifySchemaForm',
15 props: {
16 value: {
17 type: Object,
18 default: () => ({}),
19 },
20 fields: {
21 type: [Object, Array],
22 required: true,
23 },
24 rootNode: {
25 type: Object,
26 default: null,
27 },
28 defaultType: {
29 type: String,
30 default: null,
31 },
32 globalProps: {
33 type: Object,
34 default: null,
35 },
36 globalClasses: {
37 type: Object,
38 default: null,
39 },
40 context: {
41 type: Object,
42 default: () => ({}),
43 },
44 skeletonLoading: {
45 type: Boolean,
46 default: false,
47 },
48 noGutters: {
49 type: Boolean,
50 default: false,
51 },
52 nestedKeys: {
53 type: Boolean,
54 default: false,
55 },
56 submitOnEnter: {
57 type: Boolean,
58 default: false,
59 },
60 },
61 data() {
62 return {
63 clone: {},
64 validateionFailedEvent: new Event('validation-failed'),
65 };
66 },
67 computed: {
68 root() {
69 const rootNode = this.rootNode || (Vue.$schemaForm && Vue.$schemaForm.rootNode) || { type: 'row' };
70 return !this.fields.length ? this.fields : { ...rootNode, fields: this.fields };
71 },
72 objectFields() {
73 return getFields(this.root)
74 .flat(Number.POSITIVE_INFINITY)
75 .filter((field) => field.value !== undefined);
76 },
77 },
78 watch: {
79 value: {
80 handler(val) {
81 this.initialize(val);
82 },
83 immediate: true,
84 },
85 objectFields() {
86 this.initialize(this.value);
87 },
88 },
89 mounted() {
90 if (this.submitOnEnter) {
91 window.addEventListener('keyup', (event) => {
92 if (event.keyCode === 13) {
93 this.submit();
94 event.preventDefault();
95 event.stopPropagation();
96 }
97 });
98 }
99 },
100 methods: {
101 submit() {
102 if (!this.$refs.editForm.validate()) {
103 // const error = this.$refs.editForm.inputs.filter((x) => x.hasError)[0] || {};
104 // if (error) {
105 // this.validateionFailedEvent.dispatchEvent(error);
106 // }
107 return;
108 }
109
110 this.$refs.editForm.$el.querySelectorAll('input')
111 .forEach((input) => {
112 if (input.blur) {
113 input.blur();
114 }
115 });
116
117 this.$nextTick(() => {
118 const data = this.nestedKeys ? this.processNestedKeys(this.clone) : this.clone;
119 this.$emit('submit', data);
120 });
121 },
122 reset() {
123 if (this.$refs.editForm) {
124 this.initialize({});
125 this.$refs.editForm.resetValidation();
126 }
127 },
128 initialize(initial) {
129 this.clone = {
130 ...Object.assign({}, ...this.objectFields.map((field) => ({ [field.value]: null }))),
131 ...clone(initial),
132 };
133 },
134 processNestedKeys(data) {
135 const cloned = clone(data);
136 Object.keys(cloned).forEach((key) => {
137 if (!key.includes('__')) {
138 return;
139 }
140 const [parentKey, childKey] = key.split('__');
141 if (!(parentKey in cloned)) {
142 cloned[parentKey] = {};
143 }
144 cloned[parentKey][childKey] = cloned[key];
145 delete cloned[key];
146 });
147
148 return cloned;
149 },
150 },
151 render(h) {
152 const params = Vue.$schemaForm || {};
153 const options = {
154 types,
155 propsResolver,
156 ...params,
157 defaultType: this.defaultType || params.defaultType || 'text',
158 globalProps: this.globalProps || params.globalProps || { dense: true },
159 globalClasses: this.globalClasses || params.globalClasses || {},
160 $vuetify: this.$vuetify,
161 };
162
163 const tree = buildComponentsTree(this.root, options);
164 const renderedTree = renderComponentsTree(h, tree, this.clone,
165 (item) => this.$emit('input', item), {
166 context: this.context,
167 scopedSlots: this.$scopedSlots,
168 skeletonLoading: this.skeletonLoading,
169 ...options,
170 });
171
172 return h(VForm,
173 {
174 props: { lazyValidation: true },
175 on: {
176 submit: (event) => {
177 if (!this.submitOnEnter) {
178 this.submit();
179 }
180 event.preventDefault();
181 event.stopPropagation();
182 },
183 },
184 ref: 'editForm',
185 },
186 [
187 h(VContainer, {
188 class: {
189 'px-0': true,
190 'py-1': true,
191 },
192 props: {
193 // gridListMd: true,
194 fluid: true,
195 },
196 }, [renderedTree]),
197 ]);
198 },
199};
200</script>
201<style>
202.vsf-skeleton-loading .v-skeleton-loader__bone {
203 height: 70%;
204 opacity: 0.6;
205}
206</style>