1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-14 17:18:33 +00:00

Fix reactivity problems in widget configuration forms

This commit is contained in:
Petr Stribny 2025-02-24 12:08:02 +01:00
parent f98e72156a
commit 2ef2d2d299
5 changed files with 62 additions and 52 deletions
enterprise/web-frontend/modules/baserow_enterprise/dashboard/components/data_source
web-frontend/modules
core/mixins
dashboard/components

View file

@ -10,9 +10,9 @@
class="margin-bottom-2" class="margin-bottom-2"
> >
<Dropdown <Dropdown
v-model="values.aggregation_type" :value="values.aggregation_type"
:error="fieldHasErrors('aggregation_type')" :error="fieldHasErrors('aggregation_type')"
@change="v$.values.aggregation_type.$touch" @change="aggregationTypeChanged"
> >
<DropdownItem <DropdownItem
v-for="aggregation in groupedAggregationTypes" v-for="aggregation in groupedAggregationTypes"
@ -90,7 +90,7 @@ export default {
field_id: null, field_id: null,
aggregation_type: null, aggregation_type: null,
}, },
emitValuesOnReset: false, skipFirstValuesEmit: true,
} }
}, },
computed: { computed: {
@ -116,32 +116,6 @@ export default {
return this.compatibleFields.map((field) => field.id) return this.compatibleFields.map((field) => field.id)
}, },
}, },
watch: {
'values.aggregation_type': {
handler(aggregationType) {
if (
aggregationType !== null &&
aggregationType !== this.defaultValues.aggregation_type &&
this.values.field_id !== null
) {
// If both the field and aggregation type
// are selected, check if they are still
// compatible.
const aggType = this.$registry.get(
'groupedAggregation',
aggregationType
)
const field = this.tableFields.filter(
(field) => field.id === this.values.field_id
)
if (!aggType.fieldIsCompatible(field)) {
this.values.field_id = null
}
}
},
immediate: true,
},
},
mounted() { mounted() {
this.v$.$touch() this.v$.$touch()
}, },
@ -171,6 +145,17 @@ export default {
const fieldType = this.$registry.get('field', field.type) const fieldType = this.$registry.get('field', field.type)
return fieldType.iconClass return fieldType.iconClass
}, },
aggregationTypeChanged(aggregationType) {
this.values.aggregation_type = aggregationType
const aggType = this.$registry.get('groupedAggregation', aggregationType)
const field = this.tableFields.find(
(field) => field.id === this.values.field_id
)
if (field && !aggType.fieldIsCompatible(field)) {
this.values.field_id = null
}
this.v$.values.aggregation_type.$touch()
},
}, },
} }
</script> </script>

View file

@ -172,7 +172,7 @@ export default {
}, },
tableLoading: false, tableLoading: false,
databaseSelectedId: null, databaseSelectedId: null,
emitValuesOnReset: false, skipFirstValuesEmit: true,
} }
}, },
computed: { computed: {
@ -230,12 +230,15 @@ export default {
watch: { watch: {
dataSource: { dataSource: {
async handler(values) { async handler(values) {
this.setEmitValues(false)
// Reset the form to set default values // Reset the form to set default values
// again after a different widget is selected // again after a different widget is selected
await this.reset(true) await this.reset(true)
// Run form validation so that // Run form validation so that
// problems are highlighted immediately // problems are highlighted immediately
this.v$.$touch() this.v$.$touch()
await this.$nextTick()
this.setEmitValues(true)
}, },
deep: true, deep: true,
}, },

View file

@ -23,11 +23,15 @@ export default {
return { return {
// A list of values that the form allows. If null all values are allowed. // A list of values that the form allows. If null all values are allowed.
allowedValues: null, allowedValues: null,
// By setting emitValuesOnReset to false in the form's component // Setting to false make it possible to temporarily
// the values changed event won't be sent right after resetting the // prevent emitting values when they change.
// form // Use setEmitValues(value) method to include children
emitValuesOnReset: true, // forms.
isAfterReset: true, emitValues: true,
// Setting to true makes it possible to not
// emit values the first time values are set in
// the form.
skipFirstValuesEmit: false,
} }
}, },
mounted() { mounted() {
@ -38,7 +42,13 @@ export default {
watch: { watch: {
values: { values: {
handler(newValues) { handler(newValues) {
this.emitChange(newValues) if (this.skipFirstValuesEmit) {
this.skipFirstValuesEmit = false
return
}
if (this.emitValues) {
this.emitChange(newValues)
}
}, },
deep: true, deep: true,
}, },
@ -207,8 +217,6 @@ export default {
* first level of children. * first level of children.
*/ */
async reset(deep = false) { async reset(deep = false) {
this.isAfterReset = true
for (const [key, value] of Object.entries(this.getDefaultValues())) { for (const [key, value] of Object.entries(this.getDefaultValues())) {
this.values[key] = value this.values[key] = value
} }
@ -224,6 +232,15 @@ export default {
child.reset() child.reset()
) )
}, },
/**
* Sets emitValues property also to child forms.
*/
setEmitValues(value) {
this.emitValues = value
this.getChildForms((child) => 'setEmitValues' in child, true).forEach(
(child) => child.setEmitValues(value)
)
},
/** /**
* Returns if a child form has indicated it handled the error, false otherwise. * Returns if a child form has indicated it handled the error, false otherwise.
*/ */
@ -241,13 +258,7 @@ export default {
return childHandledIt return childHandledIt
}, },
emitChange(newValues) { emitChange(newValues) {
if (this.emitValuesOnReset === true || this.isAfterReset === false) { this.$emit('values-changed', newValues)
this.$emit('values-changed', newValues)
}
if (this.isAfterReset) {
this.isAfterReset = false
}
}, },
}, },
} }

View file

@ -170,7 +170,7 @@ export default {
}, },
tableLoading: false, tableLoading: false,
databaseSelectedId: null, databaseSelectedId: null,
emitValuesOnReset: false, skipFirstValuesEmit: true,
} }
}, },
computed: { computed: {
@ -227,13 +227,16 @@ export default {
}, },
watch: { watch: {
dataSource: { dataSource: {
handler(values) { async handler(values) {
this.setEmitValues(false)
// Reset the form to set default values // Reset the form to set default values
// again after a different widget is selected // again after a different widget is selected
this.reset(true) await this.reset(true)
// Run form validation so that // Run form validation so that
// problems are highlighted immediately // problems are highlighted immediately
this.v$.$validate() this.v$.$touch()
await this.$nextTick()
this.setEmitValues(true)
}, },
deep: true, deep: true,
}, },

View file

@ -71,7 +71,7 @@ export default {
title: '', title: '',
description: '', description: '',
}, },
emitValuesOnReset: false, skipFirstValuesEmit: true,
} }
}, },
validations() { validations() {
@ -98,8 +98,16 @@ export default {
}, },
watch: { watch: {
widget: { widget: {
handler(value) { async handler(value) {
this.reset(true) this.setEmitValues(false)
// Reset the form to set default values
// again after a different widget is selected
await this.reset(true)
// Run form validation so that
// problems are highlighted immediately
this.v$.$touch()
await this.$nextTick()
this.setEmitValues(true)
}, },
deep: true, deep: true,
}, },