Newer
Older
Sébastien DA ROCHA
committed
<template>

Timothee P
committed
:class="['field', { 'disabled': field.disabled }]"
:data-field_type="field.field_type"
data-test="extra-form"

Timothee P
committed
<div
v-if="field && field.field_type === 'boolean'"
:class="['ui checkbox', { 'disabled': field.disabled }]"

Timothee P
committed
<input
:id="field.name"
type="checkbox"
:checked="field.value"
:name="field.name"
@change="updateStore_extra_form"
>
<label :for="field.name">
{{ displayLabels ? field.label : '' }}
</label>
</div>

Timothee P
committed
<template v-else>
<label
v-if="displayLabels"
:for="field.name"
:class="{ required: field.is_mandatory }"
>
{{ field.label }}
</label>

Timothee P
committed
<input
v-if="field && field.field_type === 'char'"
:id="field.name"
:value="field.value"
type="text"
:name="field.name"
:required="field.is_mandatory"
@blur="updateStore_extra_form"

Timothee P
committed
<textarea
v-else-if="field && field.field_type === 'text'"
:value="field.value"
:name="field.name"
:required="field.is_mandatory"
rows="3"
@blur="updateStore_extra_form"
/>
Sébastien DA ROCHA
committed
<input

Timothee P
committed
v-else-if="field && field.field_type === 'integer'"
Sébastien DA ROCHA
committed
:id="field.name"
:value="field.value"
Sébastien DA ROCHA
committed
@change="updateStore_extra_form"
Sébastien DA ROCHA
committed
<input

Timothee P
committed
v-else-if="field && field.field_type === 'decimal'"

Timothee P
committed
:value="field.value"
type="number"
step=".01"
Sébastien DA ROCHA
committed
:name="field.name"

Timothee P
committed
:required="field.is_mandatory"
Sébastien DA ROCHA
committed
@change="updateStore_extra_form"
Sébastien DA ROCHA
committed
<input

Timothee P
committed
v-else-if="field && field.field_type === 'date'"
:value="field.value"

Timothee P
committed
type="date"
Sébastien DA ROCHA
committed
:name="field.name"
Sébastien DA ROCHA
committed
@change="updateStore_extra_form"

Timothee P
committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<Dropdown
v-else-if="field && field.field_type === 'list'"
:options="field.options"
:selected="selected_extra_form_list"
:selection.sync="selected_extra_form_list"
:required="field.is_mandatory"
:search="true"
:clearable="true"
/>
<div
v-else-if="field && field.field_type === 'multi_choices_list'"
class="checkbox_list"
>
<div
v-for="option in field.options"
:key="option"
class="ui checkbox"
>
<input
:id="option"
type="checkbox"
:checked="field.value && field.value.includes(option)"
:name="option"
@change="selectMultipleCheckbox"
>
<label :for="option">
{{ option }}
</label>
</div>
</div>
<Multiselect
v-else-if="field && field.field_type === 'pre_recorded_list'"
v-model="selectedPrerecordedValue"
:options="selectedPrerecordedListValues[field.options[0]] || []"
:options-limit="10"
:allow-empty="!field.is_mandatory"
track-by="label"
label="label"
:reset-after="false"
select-label=""
selected-label=""
deselect-label=""
:searchable="true"
:placeholder="'Recherchez une valeur de la liste pré-définie ...'"
:show-no-results="true"
:loading="loadingPrerecordedListValues"
:clear-on-select="false"
:preserve-search="false"
@search-change="search"
@select="selectPrerecordedValue"
>
<template slot="clear">
<div
v-if="selectedPrerecordedValue"
class="multiselect__clear"
@click.prevent.stop="clearPrerecordedValue"
>
<i
class="close icon"
aria-hidden="true"
/>
</div>
</template>
<span slot="noResult">
Aucun résultat.
</span>
<span slot="noOptions">
Saisissez les premiers caractères ...
</span>
</Multiselect>
</template>
Sébastien DA ROCHA
committed
</div>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import Multiselect from 'vue-multiselect';
import { isEqual } from 'lodash';
import Dropdown from '@/components/Dropdown.vue';
Sébastien DA ROCHA
committed
export default {
Sébastien DA ROCHA
committed
components: {
Dropdown,
Sébastien DA ROCHA
committed
},
props: {
field: {
type: Object,
default: null,
},
isConditionalField: {
type: Boolean,
default: false,
Sébastien DA ROCHA
committed
prerecordedListSearchQuery: null,
loadingPrerecordedListValues: false,
selectedPrerecordedValue: null,
selectedMultipleCheckbox: [],
Sébastien DA ROCHA
committed
computed: {
...mapState('feature-type', [
'selectedPrerecordedListValues'
]),
...mapState('feature', [
'extra_forms',
]),
Sébastien DA ROCHA
committed
selected_extra_form_list: {
get() {
Sébastien DA ROCHA
committed
},
set(newValue) {
//* set the value selected in the dropdown
if (this.isConditionalField) {
this.$emit('update:condition-value', newValue);
} else {
const newExtraForm = this.field;
newExtraForm['value'] = newValue;
this.$store.commit('feature/UPDATE_EXTRA_FORM', newExtraForm);
}
Sébastien DA ROCHA
committed
},
},
displayLabels() {
return this.$route.name === 'editer-signalement' || this.$route.name === 'ajouter-signalement' || this.$route.name === 'editer-attribut-signalement';
Sébastien DA ROCHA
committed
},
'field.value': function(newValue, oldValue) {
// In fast edition, prerecordedlist is not updated, thus the value stay the same
// in this case we renitialize the field. This doesn't impact usual behavior if user reselect the same option
if (this.field) {
if (this.field.field_type === 'pre_recorded_list') {
// if both values are defined but their values changed, value in form should be updated
if (newValue && oldValue && (newValue.label !== oldValue.label || newValue !== oldValue) // prevent case of having a label or directly the value
// if any of them is undefined, the form value should be updated, because in this case the value changed
// otherwise (if they are both undefined) the watcher would not called, thus we don't need to prevent this case
|| !newValue || !oldValue)
{
this.initPrerecordedXform();
}
} else if (this.field.field_type === 'multi_choices_list') {
// if array values changed, value in form should be updated, otherwise at edition in fast browsing mode, it would overide current value with previous value loaded at component creation
if (isEqual(newValue, oldValue)) {
this.initMultipleCheckboxXform();
}
prerecordedListSearchQuery(newValue) {
this.loadingPrerecordedListValues = true;
this.GET_SELECTED_PRERECORDED_LIST_VALUES({
name: this.field.options[0],
pattern: newValue
})
.then(() => {
this.loadingPrerecordedListValues = false;
})
.catch(() => {
this.loadingPrerecordedListValues = false;
});
}
if (this.field) {
if (this.field.field_type === 'pre_recorded_list') {
this.initPrerecordedXform();
} else if (this.field.field_type === 'multi_choices_list') {
this.initMultipleCheckboxXform();

Timothee P
committed
// autoset field to false if is a boolean, since user doesn't need to select it, when false value is expected
if (this.field.field_type === 'boolean' && (this.field.value === undefined || this.field.value === null)) {
this.updateStore_extra_form(false);

Timothee P
committed
}
Sébastien DA ROCHA
committed
methods: {
...mapActions('feature-type', [
'GET_SELECTED_PRERECORDED_LIST_VALUES'
]),
...mapMutations('feature', [
'UPDATE_EXTRA_FORM',
'SET_EXTRA_FORMS',
initMultipleCheckboxXform() {
this.selectedMultipleCheckbox = this.field.value || [];
},
initPrerecordedXform() {
const { options, value } = this.field;
this.loadingPrerecordedListValues = true;
this.GET_SELECTED_PRERECORDED_LIST_VALUES({
name: options[0],
pattern: ''
})
.then(() => {
this.loadingPrerecordedListValues = false;
})
.catch(() => {
this.loadingPrerecordedListValues = false;
});
if (value) {
this.selectedPrerecordedValue = { label: value.label ? value.label : value };
} else {
this.selectedPrerecordedValue = null;
}
},
Sébastien DA ROCHA
committed
updateStore_extra_form(evt) {
if (evt && evt.target) { // if called from the template
if (this.field.field_type === 'boolean') {
newValue = evt.target.checked; //* if checkbox, use "checked"
} else {
newValue = evt.target.value;
}
} else if (this.field.field_type === 'multi_choices_list') { // special case where the value is stored in the state
newValue = this.selectedMultipleCheckbox;
} else { // if the newValue was sent directly
newValue = evt;
}
//* set the value selected
if (this.isConditionalField) {
this.$emit('update:condition-value', newValue);
this.UPDATE_EXTRA_FORM({ ...this.field, ['value']: newValue });
Sébastien DA ROCHA
committed
},
if (this.field && this.field.is_mandatory && !this.field.value) {
isValid = false;
this.error = 'Ce champ est obligatoire';
} else {
this.error = null;
}
return isValid;
search(text) {
this.prerecordedListSearchQuery = text;
},
selectPrerecordedValue(e) {
this.prerecordedListSearchQuery = null;

Timothee P
committed
this.updateStore_extra_form({ target: { value: this.selectedPrerecordedValue.label } });
this.selectedPrerecordedValue = null;
this.prerecordedListSearchQuery = null;
this.updateStore_extra_form({ target: { value: null } });
},
selectMultipleCheckbox(e) {
const { checked, name } = e.target;
if (checked) {
this.selectedMultipleCheckbox.push(name);
} else {
this.selectedMultipleCheckbox = this.selectedMultipleCheckbox.filter((el) => el !== name);
}
this.updateStore_extra_form();
},
Sébastien DA ROCHA
committed
},
};
label.required:after {
content: ' *';
color: rgb(209, 0, 0);
}
.checkbox_list {
display: flex;
flex-direction: column;
.ui.checkbox {
margin: .5rem;
font-weight: normal;
}

Timothee P
committed
.multiselect__placeholder {
position: absolute;
width: calc(100% - 48px);
overflow: hidden;
text-overflow: ellipsis;

Timothee P
committed
.multiselect__tags {
position: relative;
}
/* keep font-weight from overide of semantic classes */
.multiselect__placeholder, .multiselect__content, .multiselect__tags {
font-weight: initial !important;
}
/* keep placeholder eigth */
.multiselect .multiselect__placeholder {
margin-bottom: 9px !important;
padding-top: 1px;
}
/* keep placeholder height when opening dropdown without selection */
input.multiselect__input {
padding: 3px 0 0 0 !important;
}
/* keep placeholder height when opening dropdown with already a value selected */
.multiselect__tags .multiselect__single {
padding: 1px 0 0 0 !important;
margin-bottom: 9px;
}