Skip to content
Snippets Groups Projects
Commit 00587f54 authored by Camille Blanchon's avatar Camille Blanchon
Browse files

Merge branch 'redmine-issues/20476' into 'develop'

REDMINE_ISSUE-20476 | Multiple checkbox ne conserve pas valeur initial

See merge request !752
parents b01e0eae f477c27d
No related branches found
No related tags found
1 merge request!752REDMINE_ISSUE-20476 | Multiple checkbox ne conserve pas valeur initial
...@@ -160,7 +160,6 @@ ...@@ -160,7 +160,6 @@
<script> <script>
import { mapState, mapActions, mapMutations } from 'vuex'; import { mapState, mapActions, mapMutations } from 'vuex';
import Multiselect from 'vue-multiselect'; import Multiselect from 'vue-multiselect';
import { isEqual } from 'lodash';
import Dropdown from '@/components/Dropdown.vue'; import Dropdown from '@/components/Dropdown.vue';
...@@ -223,25 +222,31 @@ export default { ...@@ -223,25 +222,31 @@ export default {
}, },
watch: { watch: {
/**
* Watches for changes in the 'field.value' and updates the form state accordingly.
* This watcher handles specific field types, ensuring their values are correctly initialized
* and updated in scenarios like fast edition mode where certain values might not be auto-refreshed.
*
* @param {*} newValue - The new value of the field.
* @param {*} oldValue - The previous value of the field before the change.
*/
'field.value': function(newValue, oldValue) { 'field.value': function(newValue, oldValue) {
// In fast edition, prerecordedlist is not updated, thus the value stay the same // Check if the field object exists.
// 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) {
// Handle pre-recorded list fields specifically.
if (this.field.field_type === 'pre_recorded_list') { if (this.field.field_type === 'pre_recorded_list') {
// if both values are defined but their values changed, value in form should be updated // Update the form value if both new and old values are defined and different,
if (newValue && oldValue && (newValue.label !== oldValue.label || newValue !== oldValue) // prevent case of having a label or directly the value // or if either value is undefined, indicating a change.
// if any of them is undefined, the form value should be updated, because in this case the value changed if ((newValue && oldValue && (newValue.label !== oldValue.label || newValue !== oldValue))
// otherwise (if they are both undefined) the watcher would not called, thus we don't need to prevent this case || !newValue || !oldValue) {
|| !newValue || !oldValue) this.initPrerecordedXform(); // Reinitialize the field to reflect the updated value.
{
this.initPrerecordedXform();
} }
} else if (this.field.field_type === 'multi_choices_list') { } 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 // For multi-choice lists, reinitialize the field if the array values have changed.
if (isEqual(newValue, oldValue)) { // This is crucial in fast edition modes to prevent overriding the current value with a stale value.
this.initMultipleCheckboxXform(); this.initMultipleCheckboxXform();
}
} }
// Reset any error states for the field.
this.error = null; this.error = null;
} }
}, },
...@@ -310,26 +315,39 @@ export default { ...@@ -310,26 +315,39 @@ export default {
this.selectedPrerecordedValue = null; this.selectedPrerecordedValue = null;
} }
}, },
/**
updateStore_extra_form(evt) { * Updates the Vuex store or component state with the new value for a form field.
* This function handles different types of form fields including boolean, multi-choice lists, and others.
*
* @param {Event|*} val - The new value or an event object.
*/
updateStore_extra_form(val) {
// Check if the field object is defined.
if (this.field) { if (this.field) {
let newValue; let newValue;
if (evt && evt.target) { // if called from the template // If the function is triggered by an event from a template input.
if (val && val.target) {
// For boolean fields (like checkboxes), use the 'checked' property.
if (this.field.field_type === 'boolean') { if (this.field.field_type === 'boolean') {
newValue = evt.target.checked; //* if checkbox, use "checked" newValue = val.target.checked;
} else { } else {
newValue = evt.target.value; // For other input types, use the 'value' property.
newValue = val.target.value;
} }
} else if (this.field.field_type === 'multi_choices_list') { // special case where the value is stored in the state } else if (this.field.field_type === 'multi_choices_list') {
// For multi-choice lists, the value is stored in component state.
newValue = this.selectedMultipleCheckbox; newValue = this.selectedMultipleCheckbox;
} else { // if the newValue was sent directly } else {
newValue = evt; // If the function is called directly with a value (not from an event).
newValue = val;
} }
//* set the value selected // Set the new value for the field.
if (this.useValueOnly) { if (this.useValueOnly) {
// If the component is used to update directly a returned value, emit an event with the new value.
this.$emit('update:value', newValue); this.$emit('update:value', newValue);
} else { } else {
this.UPDATE_EXTRA_FORM({ ...this.field, ['value']: newValue }); // Otherwise, update the Vuex store with the new value for the extra form field.
this.UPDATE_EXTRA_FORM({ ...this.field, value: newValue });
} }
} }
}, },
...@@ -361,15 +379,30 @@ export default { ...@@ -361,15 +379,30 @@ export default {
this.updateStore_extra_form({ target: { value: null } }); this.updateStore_extra_form({ target: { value: null } });
}, },
/**
* Handles the selection and deselection of checkboxes in a form.
* This function updates an array to track the selected checkboxes by their names.
* It's typically called on the change event of each checkbox.
*
* @param {Event} e - The event object from the checkbox input.
*/
selectMultipleCheckbox(e) { selectMultipleCheckbox(e) {
// Destructure the 'checked' status and 'name' of the checkbox from the event target.
const { checked, name } = e.target; const { checked, name } = e.target;
// If the checkbox is checked, add its name to the array of selected checkboxes.
// Cloning the array to allow unsaved changes detection (it wasn't working with Array.push)
if (checked) { if (checked) {
this.selectedMultipleCheckbox.push(name); this.selectedMultipleCheckbox = [...this.selectedMultipleCheckbox, name];
} else { } else {
// If the checkbox is unchecked, remove its name from the array.
this.selectedMultipleCheckbox = this.selectedMultipleCheckbox.filter((el) => el !== name); this.selectedMultipleCheckbox = this.selectedMultipleCheckbox.filter((el) => el !== name);
} }
// Call a method to update the Vuex store or component state with the latest selection.
this.updateStore_extra_form(); this.updateStore_extra_form();
}, },
}, },
}; };
</script> </script>
......
...@@ -423,24 +423,32 @@ const feature = { ...@@ -423,24 +423,32 @@ const feature = {
return false; return false;
}); });
}, },
/**
* Initializes extra forms based on the current feature type and its custom fields.
* This function retrieves custom fields for the current feature type, assigns values to them based on the current feature's properties,
* and commits them to the store to be displayed in the form.
*
* @param {Object} context - The Vuex action context, including state, rootGetters, and commit function.
*/
INIT_EXTRA_FORMS({ state, rootGetters, commit }) { INIT_EXTRA_FORMS({ state, rootGetters, commit }) {
const feature = state.currentFeature; const feature = state.currentFeature; // Current feature being edited or viewed.
const featureType = rootGetters['feature-type/feature_type']; const featureType = rootGetters['feature-type/feature_type']; // Retrieves the feature type from root getters.
const customFields = featureType.customfield_set; const customFields = featureType.customfield_set; // Custom fields defined for the feature type.
if (customFields) { if (customFields) {
//* retrieve 'name', 'options', 'position' from current feature_type data to display in the form
commit('SET_EXTRA_FORMS', commit('SET_EXTRA_FORMS',
activateFieldsNforceValues( activateFieldsNforceValues( // A hypothetical function to activate fields and enforce their values.
customFields.map((field) => { customFields.map((field) => {
//* add value field to extra forms from feature_type and existing values if feature is defined // Determines the initial value for the field
field.value = feature.properties ? feature.properties[field.name] : findXformValue(feature, field); let value = feature.properties ? feature.properties[field.name] : findXformValue(feature, field);
//* if a boolean has a null value, set it to false to allow comparison with false later on (for instance with forced value) // If the field is a boolean and the value is null, sets it to false
if (field.field_type === 'boolean' && field.value === null) field.value = false; if (field.field_type === 'boolean' && value === null) {
return field; value = false;
}
// Returns a new object with the updated value and the rest of the field's properties
return { ...field, value };
}) })
).sort((a, b) => a.position - b.position) //* order according to user defined position ).sort((a, b) => a.position - b.position) // Sorts fields by their user-defined position.
); );
} }
}, },
......
...@@ -269,23 +269,36 @@ export default { ...@@ -269,23 +269,36 @@ export default {
...mapState('map', [ ...mapState('map', [
'basemaps', 'basemaps',
]), ]),
/**
* Checks if there are any unsaved changes in the form compared to the current feature's properties.
* This function is useful for prompting the user before they navigate away from a page with unsaved changes.
*
* @returns {boolean} - Returns true if there are unsaved changes; otherwise, returns false.
*/
hasUnsavedChange() { hasUnsavedChange() {
if (this.project.fast_edition_mode && this.form && this.currentFeature && this.currentFeature.properties) { // Ensure we are in edition mode and all required objects are present.
if (this.project && this.project.fast_edition_mode &&
this.form && this.currentFeature && this.currentFeature.properties) {
// Check for changes in title, description, and status.
if (this.form.title !== this.currentFeature.properties.title) return true; if (this.form.title !== this.currentFeature.properties.title) return true;
if (this.form.description.value !== this.currentFeature.properties.description) return true; if (this.form.description.value !== this.currentFeature.properties.description) return true;
if (this.form.status.value !== this.currentFeature.properties.status) return true; if (this.form.status.value !== this.currentFeature.properties.status) return true;
// Iterate over extra forms to check for any changes.
for (const xForm of this.$store.state.feature.extra_forms) { for (const xForm of this.$store.state.feature.extra_forms) {
const originalValue = this.currentFeature.properties[xForm.name]; const originalValue = this.currentFeature.properties[xForm.name];
// Check if the form value has changed, considering edge cases for undefined, null, or empty values.
if ( if (
!isEqual(xForm.value, originalValue) && // check if values changed !isEqual(xForm.value, originalValue) && // Check if values have changed.
!(!xForm.value && !originalValue) // if the value is not defined, null, an empty string or a boolean with false, no need to warn the user before leaving page without saving (when a conditional field is unactivated or in case of boolean not set by user the value is null which is equivalent to false) !(!xForm.value && !originalValue) // Ensure both aren't undefined/null/empty, treating null as equivalent to false for unactivated conditionals or unset booleans.
) { ) {
console.log('In custom form [',xForm.name, '], the current form value [', xForm.value, '] differs from original value [', originalValue, ']'); // Log the difference for debugging purposes.
console.log(`In custom form [${xForm.name}], the current form value [${xForm.value}] differs from original value [${originalValue}]`);
return true; return true;
} }
} }
} }
// If none of the above conditions are met, return false indicating no unsaved changes.
return false; return false;
}, },
......
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