Skip to content
Snippets Groups Projects
Commit b90cf519 authored by Bastien Abadie's avatar Bastien Abadie
Browse files

Merge branch 'list-user-config' into 'master'

List type parameters in form configuration

Closes #1025

See merge request !1301
parents 5a803686 d3a5a2c1
No related branches found
No related tags found
1 merge request!1301List type parameters in form configuration
<template>
<div>
<div
class="field"
v-for="(item, i) in newList"
:key="i"
>
<div
class="field has-addons"
>
<div class="control">
<input
class="input"
:value="item"
:class="{ 'is-danger': itemError[i] }"
v-on:input="updateItem(i, $event.target.value)"
/>
</div>
<div class="control">
<a
class="button is-danger is-outlined"
title="Remove item from list"
v-on:click="removeItem(i)"
>
<i class="icon-minus"></i>
</a>
</div>
</div>
<p class="help is-danger mt-0" v-if="itemError[i]">{{ itemError[i] }}</p>
</div>
<p>
<a
class="button is-primary mt-1"
title="Add new row"
v-on:click="addRow"
>
<i class="icon-plus"></i>
</a>
</p>
</div>
</template>
<script>
import FIELDS from '.'
export default {
props: {
field: {
type: Object,
required: true
},
// Array or String because if there is no default value set, value is an empty string
value: {
type: [Array, String],
required: true,
validator (value) {
return Array.isArray(value) || value === ''
}
}
},
data: () => ({
FIELDS,
newList: [],
newItem: null,
itemError: [],
validatedList: []
}),
mounted () {
if (!this.value) return
this.newList = [...this.value]
this.validatedList = [...this.value]
this.itemError = new Array(this.value.length).fill(null)
},
computed: {
// Remove blank items from input list
cleanList () {
return this.validatedList.filter((item) => {
return String(item).trim().length > 0
})
}
},
methods: {
addRow () {
this.itemError.push(null)
this.newList.push('')
},
removeItem (i) {
this.newList.splice(i, 1)
this.$delete(this.itemError, i)
},
updateItem (i, newValue) {
if (this.newList[i] === newValue) return
// Do not keep the last valid value in the list if the field is emptied
if (!String(newValue).trim().length) {
this.newList.splice(i, 1, newValue)
this.itemError[i] = null
}
this.newList.splice(i, 1, newValue)
this.validateFields()
},
validateFields () {
for (const [i, item] of this.newList.entries()) {
if (String(item).trim().length && FIELDS[this.field.subtype].validate) {
try {
const validated = FIELDS[this.field.subtype].validate(item, this.field)
this.itemError[i] = null
this.validatedList.splice(i, 1, validated)
} catch (e) {
this.itemError[i] = e.message
}
} else this.validatedList[i] = item
}
}
},
watch: {
cleanList: {
handler (newValue, oldValue) {
if (newValue === oldValue) return
/*
* If there are errors on some of the list items, emit a list containing an error which gets
* checked by the validation function so that the parent component blocks configuration creation.
*/
if (!Object.values(this.itemError).every(value => value === null)) this.$emit('input', [Error('Errors on one or more list item(s).')])
else this.$emit('input', newValue)
},
immediate: true
}
}
}
</script>
<style lang="sass" scoped>
.control {
padding-top: 2px;
padding-bottom: 2px;
padding-left: 2px;
vertical-align: middle;
}
.button.is-primary {
margin-left: 2px;
}
</style>
......@@ -4,6 +4,7 @@ import ChoicesField from './ChoicesField'
import StringField from './StringField'
import BooleanField from './BooleanField'
import DictField from './DictField'
import ListField from './ListField'
import { toNumber } from 'lodash'
export default {
......@@ -50,5 +51,12 @@ export default {
// Values should be of type String
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, String(v).toString()]))
}
},
list: {
component: ListField,
validate (value, field) {
if (!Array.isArray(value) || Object.values(value).some(value => value instanceof Error)) throw new Error(`Value must be a valid list of ${field?.subtype}.`)
return value
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment