Skip to content

Commit

Permalink
fix(vfg): input model reactivity (#1373)
Browse files Browse the repository at this point in the history
* fix(vfg): input model reactivity

* fix(*): reactivity logic and tester

* fix(*): ts error

* fix(*): keep model reactive and remove watcher (#1380)

---------

Co-authored-by: Yi Yang <Leopoldthecoder@users.noreply.github.com>
  • Loading branch information
kaiarrowood and Leopoldthecoder authored May 1, 2024
1 parent 46b157a commit c0c35ff
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 18 deletions.
59 changes: 59 additions & 0 deletions packages/core/forms/sandbox/FieldTester.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<template>
<div class="sandbox-container">
<h3>Controls</h3>
<KInput
v-model="defaultVal"
label="Default"
readonly
/>
<KInput
v-model="newVal"
label="New Value"
/>

<button @click="setNewVal">
Update Model
</button>

<h3>My Form</h3>
<VueFormGenerator
:model="formModel"
:schema="formSchema"
@model-updated="(model: Record<string, any>, schema: string) => handleModelUpdated(model, schema)"
/>

<code>{{ formModel }}</code>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const formSchema = ref({
fields: [
{
type: 'input',
model: 'cat_name',
inputType: 'text',
label: 'Cat Name',
},
],
})
// test value displays on load
const defaultVal = ref('TK Meowstersmith')
const newVal = ref('')
const formModel = ref<Record<string, any>>({
cat_name: defaultVal.value,
})
// verify model updated reflects text input events
const handleModelUpdated = (model: Record<string, any>, schema: string): void => {
formModel.value[schema] = model
}
// test programmatic updates to model
const setNewVal = (): void => {
formModel.value.cat_name = newVal.value
}
</script>
28 changes: 15 additions & 13 deletions packages/core/forms/src/composables/useAbstractFields.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, ref } from 'vue'
import { computed, ref, type Ref } from 'vue'
import type { DebouncedFunc } from 'lodash-es'
import debounce from 'lodash-es/debounce'
import forEach from 'lodash-es/forEach'
Expand All @@ -10,8 +10,8 @@ import uniqueId from 'lodash-es/uniqueId'
import validators from '../generator/utils/validators'
import { slugifyFormID } from '../generator/utils/schema'

export default function useAbstractFields(formData: {
model?: Record<string, any>,
interface AbstractFieldParams {
model?: Ref<Record<string, any> | undefined>,
schema: Record<string, any>,
formOptions?: Record<string, any>,
disabled?: boolean,
Expand All @@ -24,7 +24,9 @@ export default function useAbstractFields(formData: {
errors: any[]
field: Record<string, any>
}) => void
}) {
}

export default function useAbstractFields(formData: AbstractFieldParams) {
const errors = ref<string[]>([])
const debouncedValidateFunc = ref<DebouncedFunc<(calledParent?: any) => any[]> | null>(null)

Expand Down Expand Up @@ -56,9 +58,9 @@ export default function useAbstractFields(formData: {
let val

if (isFunction(objGet(formData.schema, 'get'))) {
val = formData.schema.get(formData.model)
val = formData.schema.get(formData.model?.value)
} else {
val = objGet(formData.model, formData.schema.model)
val = objGet(formData.model?.value, formData.schema.model)
}

return formatValueToField(val)
Expand Down Expand Up @@ -99,9 +101,9 @@ export default function useAbstractFields(formData: {

forEach(validators, validator => {
if (validateAsync) {
results.push(validator(value.value, formData.schema, formData.model))
results.push(validator(value.value, formData.schema, formData.model?.value))
} else {
const result = validator(value.value, formData.schema, formData.model)
const result = validator(value.value, formData.schema, formData.model?.value)

if (result && isFunction(result.then)) {
result.then((err: any) => {
Expand Down Expand Up @@ -135,7 +137,7 @@ export default function useAbstractFields(formData: {
})

if (isFunction(formData.schema?.onValidated)) {
formData.schema.onValidated(formData.model, fieldErrors, formData.schema)
formData.schema.onValidated(formData.model?.value, fieldErrors, formData.schema)
}

if (!calledParent) {
Expand Down Expand Up @@ -176,20 +178,20 @@ export default function useAbstractFields(formData: {
let changed = false

if (isFunction(formData.schema.set)) {
formData.schema.set(formData.model, newValue)
formData.schema.set(formData.model?.value, newValue)
changed = true
} else if (formData.schema.model) {
setModelValueByPath(formData.schema.model, newValue)
changed = true
}

if (changed) {
if (formData.emitModelUpdated && formData.model) {
if (formData.emitModelUpdated && formData.model?.value) {
formData.emitModelUpdated({ value: newValue, model: formData.schema.model })
}

if (isFunction(formData.schema.onChanged)) {
formData.schema.onChanged(formData.model, newValue, oldValue, formData.schema)
formData.schema.onChanged(formData.model?.value, newValue, oldValue, formData.schema)
}

if (objGet(formData.formOptions, 'validateAfterChanged', false) === true) {
Expand Down Expand Up @@ -228,7 +230,7 @@ export default function useAbstractFields(formData: {
// strip a leading dot
pathStr = pathStr.replace(/^\./, '')

let dataModel = formData.model || {}
let dataModel = formData.model?.value || {}
let index = 0
const arr = pathStr.split('.')
const arrLength = arr.length
Expand Down
8 changes: 5 additions & 3 deletions packages/core/forms/src/generator/fields/core/FieldInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
:type="inputType"
:width="schema.width"
@blur="onBlur"
@input="onInput"
@update:model-value="onInput"
/>
</div>
</template>

<script lang="ts" setup>
import { computed, ref, onBeforeMount, onMounted, type PropType } from 'vue'
import { computed, ref, onBeforeMount, onMounted, toRefs, type PropType } from 'vue'
import type { DebouncedFunc } from 'lodash-es'
import fecha from 'fecha'
import debounce from 'lodash-es/debounce'
Expand Down Expand Up @@ -74,8 +74,10 @@ const emit = defineEmits<{
(event: 'modelUpdated', value: any, model: Record<string, any>): void
}>()
const propsRefs = toRefs(props)
const { updateModelValue, getFieldID, clearValidationErrors, value: inputValue } = composables.useAbstractFields({
model: props.model,
model: propsRefs.model,
schema: props.schema,
formOptions: props.formOptions,
emitModelUpdated: (data: { value: any, model: Record<string, any> }): void => {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/forms/src/generator/fields/core/FieldLabel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</template>

<script lang="ts" setup>
import type { PropType } from 'vue'
import { toRefs, type PropType } from 'vue'
import composables from '../../../composables'
const props = defineProps({
Expand All @@ -34,8 +34,9 @@ const props = defineProps({
},
})
const propsRefs = toRefs(props)
const { getFieldID, value: labelValue } = composables.useAbstractFields({
model: props.model,
model: propsRefs.model,
schema: props.schema,
formOptions: props.formOptions,
})
Expand Down

0 comments on commit c0c35ff

Please sign in to comment.