Skip to content

Commit

Permalink
Refactor updates to deal with recursive objects.
Browse files Browse the repository at this point in the history
  • Loading branch information
mrichar1 committed Feb 22, 2024
1 parent c954fb5 commit c517c9e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 16 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@uoe-eng/tabularasa",
"version": "1.30.0",
"version": "1.31.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build --target lib --name tabularasa src/index.js",
Expand Down
55 changes: 40 additions & 15 deletions src/components/TRDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@
</template>

<script setup>
import { computed, defineEmits, defineProps, onMounted, reactive, ref, toRefs, watch } from 'vue'
import { computed, defineEmits, defineProps, onMounted, ref, toRefs, watch } from 'vue'
import Button from 'primevue/button'
import { trBus } from '@/index'
import merge from 'lodash/merge'
import set from 'lodash/set'
import { TYPERE } from '@/helpers'
Expand Down Expand Up @@ -78,7 +77,7 @@ const emit = defineEmits(['close'])
// Array of refs to the field components
let fieldComponents = ref([])
// We start with an empty object and update it as fields change
let newItem = reactive({})
let newItem = ref({})
// Fields to display in the card (from schema)
let fields = configuration.value.fields
// Update field validity on 'valid' events
Expand All @@ -91,16 +90,16 @@ onMounted(() => {
// Add field name and value from input component to newItem
for (let field of fieldComponents.value) {
if (field.fieldValue) {
set(newItem, field.field, field.fieldValue)
set(newItem.value, field.field, field.fieldValue)
}
}
}
})
const onBlur = (field) => {
// Emit if the blurred field's value has changed
if (field in newItem) {
trBus.emit(`TRDetail:blur:${props.name}`, [props.item, { [field]: newItem[field] }])
if (field in newItem.value) {
trBus.emit(`TRDetail:blur:${props.name}`, [props.item, { [field]: newItem.value[field] }])
}
}
Expand All @@ -110,7 +109,7 @@ const onClose = () => {
}
const onRefresh = () => {
// Empty any values already set in newItem
Object.keys(newItem).forEach((key) => delete newItem[key])
Object.keys(newItem.value).forEach((key) => delete newItem.value[key])
trBus.emit(`TRDetail:refresh:${props.name}`)
}
const maxButtonCount = computed(() => {
Expand Down Expand Up @@ -145,7 +144,8 @@ const onUpdate = (field, event) => {
let fld = field.field.replace(TYPERE, '')
// Parse dot-notation field name into a nested object using _.set
let newObj = set({}, fld, event)
merge(newItem, newObj)
// Use spread notation to shallow copy - Object.assign causes side-effects in deep/recursive objects
newItem.value = { ...newItem.value, ...newObj }
if (!field.ignoreField) {
// Emit just the changed field
trBus.emit(`TRDetail:update:${props.name}`, [props.item, newObj])
Expand Down Expand Up @@ -180,7 +180,7 @@ const recurseRemove = (obj, props) => {
const onSave = () => {
// Remove ignored fields from save data
let saveItem = newItem
let saveItem = newItem.value
for (let field of fields) {
if (field.ignoreField) {
saveItem = recurseRemove(saveItem, field.field.split('.'))
Expand All @@ -190,14 +190,39 @@ const onSave = () => {
emit('close')
}
watch([newItem, validFields.value], ([nNewItem, newValid]) => {
// If there are no edits, or any False values in valid, disable Save button
if (Object.keys(nNewItem).length == 0 || Object.values(newValid).some((x) => x === false)) {
saveDisabled.value = true
} else {
saveDisabled.value = false
const toggleSave = () => {
saveDisabled.value = true
if (Object.keys(newItem.value).length == 0 || Object.values(validFields.value).some((x) => x === false)) {
// Leave disabled if no new items, or invalid fields
return
}
for (let [key, val] of Object.entries(newItem.value)) {
// Allow saving if new key or changed value
if (!(key in item.value) || (key in item.value && item.value[key] !== val)) {
saveDisabled.value = false
break
}
}
}
watch(newItem, () => {
// Update save status when field values change
toggleSave()
})
// FIXME: validFields has to be watched as well due to PrimeVue bug: https://github.com/primefaces/primevue/issues/4338
// This triggers updates when autocomplete is mid-edit, firing watcher for newItem
// Field is still valid until focus is lost, so Save is enabled
// We therefore watch validFields as well to disable Save when it eventually catches up
// We can't combine this into a single watcher with newItem, since it can be recursive which breaks with 'deep: true'
watch(
validFields,
() => {
// Update save status when field validity changes
toggleSave()
},
{ deep: true }
)
</script>

<style>
Expand Down

0 comments on commit c517c9e

Please sign in to comment.