1313 :control =" control"
1414 :submited =" submited"
1515 @change =" valueChange"
16+ @blur =" onBlur"
1617 >
1718 <template v-slot :customField =" props " >
1819 <div
2526 :name =" slot"
2627 :control =" normalizedControls[slot]"
2728 :onChange =" props.onChange"
28- :onFocus =" props.onFocus"
2929 :onBlur =" props.onBlur"
3030 ></slot >
3131 </div >
3838import {
3939 defineComponent ,
4040 PropType ,
41- reactive ,
4241 ref ,
4342 Ref ,
4443 computed ,
4544 onMounted ,
4645 watch ,
4746 inject ,
47+ toRaw ,
4848} from ' vue' ;
49- import { DynamicForm } from ' ./form' ;
49+ import { diff } from ' deep-object-diff' ;
50+
5051import DynamicInput from ' ../dynamic-input/DynamicInput.vue' ;
5152
52- import { FieldTypes , FormControl , InputType } from ' @/core/models' ;
53+ import { DynamicForm , FieldTypes , FormControl , InputType } from ' @/core/models' ;
5354import { dynamicFormsSymbol } from ' @/useApi' ;
54- import { removeEmpty } from ' @/core/utils/helpers' ;
55+ import { deepClone , hasValue , removeEmpty } from ' @/core/utils/helpers' ;
5556
56- /* import { warn } from '../../core/utils/warning';
57- */
5857const props = {
5958 form: {
6059 type: Object as PropType <DynamicForm >,
@@ -80,31 +79,11 @@ export default defineComponent({
8079 components ,
8180 setup(props , ctx ) {
8281 const { options } = inject (dynamicFormsSymbol );
82+ const cache = deepClone (toRaw (props .form .fields ));
8383
8484 const controls: Ref <FormControl <InputType >[]> = ref ([]);
85- const formValues = reactive ({});
8685 const submited = ref (false );
8786
88- onMounted (() => {
89- mapControls ();
90- initValues ();
91- });
92- // TODO: enable again when plugin theme option is available
93-
94- /* const validTheme = computed(
95- () => options.theme && AVAILABLE_THEMES.includes(options.theme),
96- );
97-
98- if (!validTheme.value) {
99- warn(
100- `There isn't a theme: ${
101- options.theme
102- } just yet, please choose one of the available themes: ${AVAILABLE_THEMES.join(
103- ', ',
104- )}`,
105- );
106- } */
107-
10887 const deNormalizedScopedSlots = computed (() => Object .keys (ctx .slots ));
10988
11089 const normalizedControls = computed (() => {
@@ -120,6 +99,22 @@ export default defineComponent({
12099 return ! hasInvalidControls ;
121100 });
122101
102+ const formValues = computed (() => {
103+ return removeEmpty (
104+ controls .value .reduce ((prev , curr ) => {
105+ const obj = {};
106+ obj [curr .name ] =
107+ curr .type === FieldTypes .NUMBER
108+ ? parseFloat (` ${curr .value } ` )
109+ : curr .value ;
110+ return {
111+ ... prev ,
112+ ... obj ,
113+ };
114+ }, {}),
115+ );
116+ });
117+
123118 const errors = computed (() => {
124119 return controls .value
125120 ? controls .value .reduce ((prev , curr ) => {
@@ -160,12 +155,7 @@ export default defineComponent({
160155 }
161156 });
162157
163- function valueChange(changedValue : Record <string , unknown >) {
164- Object .assign (formValues , changedValue );
165- ctx .emit (' change' , removeEmpty (formValues ));
166- }
167-
168- function mapControls(empty ? : boolean ) {
158+ function mapControls(empty = false ) {
169159 const controlArray =
170160 Object .entries (props .form ?.fields ).map (
171161 ([key , field ]: [string , InputType ]) =>
@@ -192,6 +182,69 @@ export default defineComponent({
192182 controls .value = controlArray ;
193183 }
194184 }
185+ function findControlByName(name : string | unknown ) {
186+ const updatedCtrl = controls .value .find (control => control .name === name );
187+ return updatedCtrl ;
188+ }
189+
190+ function valueChange(event : Record <string , unknown >) {
191+ if (event && hasValue (event .value )) {
192+ const updatedCtrl = findControlByName (event .name );
193+ if (updatedCtrl ) {
194+ updatedCtrl .value = event .value as string ;
195+ updatedCtrl .dirty = true ;
196+ validateControl (updatedCtrl );
197+ }
198+ ctx .emit (' change' , formValues .value );
199+ }
200+ }
201+
202+ function onBlur(control : FormControl <InputType >) {
203+ const updatedCtrl = findControlByName (control .name );
204+ if (updatedCtrl ) {
205+ updatedCtrl .touched = true ;
206+ }
207+ }
208+
209+ function validateControl(control : FormControl <InputType >) {
210+ if (control .validations ) {
211+ const validation = control .validations .reduce ((prev , curr ) => {
212+ const val =
213+ typeof curr .validator === ' function'
214+ ? curr .validator (control )
215+ : null ;
216+ if (val !== null ) {
217+ const [key, value] = Object .entries (val )[0 ];
218+ const obj = {};
219+ obj [key ] = {
220+ value ,
221+ text: curr .text ,
222+ };
223+ return {
224+ ... prev ,
225+ ... obj ,
226+ };
227+ }
228+ return {
229+ ... prev ,
230+ };
231+ }, {});
232+ control .errors = validation ;
233+ control .valid = Object .keys (validation ).length === 0 ;
234+ }
235+ }
236+
237+ function detectChanges(fields ) {
238+ const changes = diff (cache , deepClone (fields ));
239+ Object .entries (changes ).forEach (([key , value ]) => {
240+ let ctrl = findControlByName (key );
241+ if (ctrl ) {
242+ Object .entries (value ).forEach (([change , newValue ]) => {
243+ ctrl [change ] = newValue ;
244+ });
245+ }
246+ });
247+ }
195248
196249 function resetForm() {
197250 mapControls (true );
@@ -208,33 +261,22 @@ export default defineComponent({
208261 }
209262 }
210263
211- function initValues() {
212- Object .assign (
213- formValues ,
214- controls .value
215- ? controls .value .reduce ((prev , curr ) => {
216- const obj = {};
217- obj [curr .name ] =
218- curr .type === FieldTypes .NUMBER
219- ? parseFloat (` ${curr .value } ` )
220- : curr .value ;
221- return {
222- ... prev ,
223- ... obj ,
224- };
225- }, {})
226- : {},
227- );
228- ctx .emit (' changed' , formValues );
229- }
264+ watch (
265+ () => props .form .fields ,
266+ fields => {
267+ detectChanges (fields );
268+ },
269+ {
270+ deep: true ,
271+ },
272+ );
230273
231- watch ( props . form . fields , () => {
274+ onMounted ( () => {
232275 mapControls ();
233276 });
234277
235278 return {
236279 controls ,
237- form: props .form ,
238280 valueChange ,
239281 formValues ,
240282 handleSubmit ,
@@ -244,6 +286,7 @@ export default defineComponent({
244286 normalizedControls ,
245287 submited ,
246288 formattedOptions ,
289+ onBlur ,
247290 };
248291 },
249292});
0 commit comments