fix form state for dropdown controls

minor cleanups
This commit is contained in:
2026-07-06 13:32:37 +02:00
parent 158892bd3e
commit 1daa5c7409
4 changed files with 76 additions and 53 deletions
+4
View File
@@ -0,0 +1,4 @@
# Regole e Convenzioni del Progetto elixForms Custom Pages
## Gestione ID dei form element
Gli ID dei campi del form (es. nel Dropdown, Checkbox, TextField) che vengono creati con i vari metodi `create...` in `ElixFormsComponentAbstract.tsx` non devono mai essere cambiati o manipolati (es. aggiungendo suffissi come `_dropdown`), poiché vengono ricevuti e inviati da una pagina iniziale che si basa strettamente sul loro nome e ID esatto. In caso di conflitti di ID (es. dovuti a input nascosti), il suffisso va applicato agli altri elementi (come l'input hidden) e MAI all'elemento principale visibile.
+64 -45
View File
@@ -59,30 +59,30 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
"ELANG" "ELANG"
]; ];
private createMandatoryFormFields(queryParams: URLSearchParams) : JSX.Element { private createMandatoryFormFields(queryParams: URLSearchParams): JSX.Element {
const hiddenInputs: JSX.Element[] = []; const hiddenInputs: JSX.Element[] = [];
// Create a hidden input for each mandatory Elix parameter // Create a hidden input for each mandatory Elix parameter
this.mandatoryFormFieldNames.forEach(paramName => { this.mandatoryFormFieldNames.forEach(paramName => {
const value = queryParams.get(paramName) ?? ""; const value = queryParams.get(paramName) ?? "";
// Create the input element // Create the input element
hiddenInputs.push(this.createHiddenInput(paramName)); hiddenInputs.push(this.createHiddenInput(paramName));
}); });
return <>{hiddenInputs}</>; return <>{hiddenInputs}</>;
} }
private createAdditionalFormFields() : React.ReactElement { private createAdditionalFormFields(): React.ReactElement {
const schema = JSON.parse(this.props.additionalFieldsJson || "[]"); const schema = JSON.parse(this.props.additionalFieldsJson || "[]");
return ( return (
<> <>
{schema.map((field: { key: React.Key | null | undefined; }) => ( {schema.map((field: { key: React.Key | null | undefined; }) => (
<div key={field.key}> <div key={field.key}>
{this.renderField(field)} {this.renderField(field)}
</div> </div>
))} ))}
</> </>
); );
} }
@@ -113,7 +113,11 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
return this.createCustomFormFields(formFieldFactory); return this.createCustomFormFields(formFieldFactory);
} }
protected renderExtraContent(): JSX.Element | null { protected renderExtraContentPre(): JSX.Element | null {
return null;
}
protected renderExtraContentPost(): JSX.Element | null {
return null; return null;
} }
@@ -176,14 +180,16 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
{environmentMessage && <div>{environmentMessage}</div>} {environmentMessage && <div>{environmentMessage}</div>}
{description && <div>{description}</div>} {description && <div>{description}</div>}
{this.renderExtraContentPre()}
<form action="https://procedure.unipr.it/rwe2/ComeBackToElixAndSave" method="post" acceptCharset="ISO-8859-1"> <form action="https://procedure.unipr.it/rwe2/ComeBackToElixAndSave" method="post" acceptCharset="ISO-8859-1">
{this.createMandatoryFormFields(queryParams)} {this.createMandatoryFormFields(queryParams)}
{this.createAdditionalFormFields()} {this.createAdditionalFormFields()}
{this.renderCustomFormFields()} {this.renderCustomFormFields()}
<input type="submit" value="Submit"/> <input type="submit" value="Submit" />
</form> </form>
{this.renderExtraContent()} {this.renderExtraContentPost()}
</div> </div>
</div> </div>
</div> </div>
@@ -212,8 +218,8 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
); );
} }
private createCheckboxInput(paramName: string, label: string, values: Array<ElixFormsCheckboxOption>) : JSX.Element { private createCheckboxInput(paramName: string, label: string, values: Array<ElixFormsCheckboxOption>): JSX.Element {
const checkedValues = QueryParamHelper.getCheckedFromQuery(paramName); const checkedValues = QueryParamHelper.getCheckedFromQuery(paramName);
if (!this.checkboxValues.get(paramName)) { if (!this.checkboxValues.get(paramName)) {
this.checkboxValues.set(paramName, checkedValues); this.checkboxValues.set(paramName, checkedValues);
@@ -234,26 +240,30 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
} else if (!checked && checkboxIndex !== -1) { } else if (!checked && checkboxIndex !== -1) {
currentCheckboxValues.splice(checkboxIndex, 1); currentCheckboxValues.splice(checkboxIndex, 1);
} }
this.state.formData[paramName] = currentCheckboxValues.join(',').trim() ?? ''; const newValue = currentCheckboxValues.join(',').trim();
//this.setState({ formData: { ...this.state.formData, [paramName]: currentCheckboxValues.join(',').trim() ?? '' } }, () => this.setState({ formData: { ...this.state.formData, [paramName]: newValue } }, () => {
console.log(`Checkbox ${id} changed to ${checked}. Current values for ${paramName}: ${this.state.formData[paramName]}`); console.log(`Checkbox ${id} changed to ${checked}. Current values for ${paramName}: ${this.state.formData[paramName]}`);
//); });
}} }}
/> />
); );
}); });
const currentValue = this.state.formData[paramName] !== undefined
? this.state.formData[paramName]
: (this.checkboxValues.get(paramName)?.join(',').trim() ?? '');
return new ElixFormsElement( return new ElixFormsElement(
<><FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label></>, <><FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label></>,
<><FluentUI.Stack tokens={stackTokens}> <><FluentUI.Stack tokens={stackTokens}>
{checkboxes} {checkboxes}
</FluentUI.Stack> </FluentUI.Stack>
<input type='hidden' id={paramName} name={paramName} value={this.state.formData[paramName] ?? ''} /> <input type='hidden' id={paramName} name={paramName} value={currentValue} />
</> </>
).render(); ).render();
} }
private createRadioInput(paramName: string, label: string, values: Array<ElixFormsRadioOption>, required: boolean = false) : JSX.Element { private createRadioInput(paramName: string, label: string, values: Array<ElixFormsRadioOption>, required: boolean = false): JSX.Element {
const radioValue = QueryParamHelper.getOptionFromQuery(paramName); const radioValue = QueryParamHelper.getOptionFromQuery(paramName);
const radios: FluentUI.IChoiceGroupOption[] = []; const radios: FluentUI.IChoiceGroupOption[] = [];
@@ -289,7 +299,7 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
).render(); ).render();
} }
private createBooleanInput(paramName: string, label: string, required: boolean = false) : JSX.Element { private createBooleanInput(paramName: string, label: string, required: boolean = false): JSX.Element {
const boolValue = QueryParamHelper.getOptionFromQuery(paramName); const boolValue = QueryParamHelper.getOptionFromQuery(paramName);
const radios: FluentUI.IChoiceGroupOption[] = []; const radios: FluentUI.IChoiceGroupOption[] = [];
@@ -325,9 +335,9 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
).render(); ).render();
} }
private createTextAreaInput(paramName: string, label: string, required: boolean = false) : JSX.Element { private createTextAreaInput(paramName: string, label: string, required: boolean = false): JSX.Element {
const textareaValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; const textareaValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
return new ElixFormsElement( return new ElixFormsElement(
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>, <FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
<FluentUI.TextField id={paramName} name={paramName} defaultValue={textareaValue} multiline rows={4} required={required} className='isiportalPartialAdminFormFieldMultiLineText' <FluentUI.TextField id={paramName} name={paramName} defaultValue={textareaValue} multiline rows={4} required={required} className='isiportalPartialAdminFormFieldMultiLineText'
onChange={(event, value) => { onChange={(event, value) => {
@@ -339,7 +349,7 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
).render(); ).render();
} }
private createTextInput(paramName: string, label: string, required: boolean = false) : JSX.Element { private createTextInput(paramName: string, label: string, required: boolean = false): JSX.Element {
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
return new ElixFormsElement( return new ElixFormsElement(
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>, <FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
@@ -353,16 +363,16 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
).render(); ).render();
} }
private createHiddenInput(paramName: string) : JSX.Element { private createHiddenInput(paramName: string): JSX.Element {
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
return <><input type='text' id={paramName} name={paramName} defaultValue={textValue} /><br/></>; return <><input type='text' id={paramName} name={paramName} defaultValue={textValue} /><br /></>;
} }
private createNumberInput(paramName: string, label: string, required: boolean = false) : JSX.Element { private createNumberInput(paramName: string, label: string, required: boolean = false): JSX.Element {
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
return new ElixFormsElement( return new ElixFormsElement(
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>, <FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
<FluentUI.TextField id={paramName} name={paramName} defaultValue={textValue} type="number" required={required} className='isiportalPartialAdminFormFieldSingleLineText' <FluentUI.TextField id={paramName} name={paramName} defaultValue={textValue} type="number" required={required} className='isiportalPartialAdminFormFieldSingleLineText'
onChange={(event, value) => { onChange={(event, value) => {
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () => this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
console.log(`NumberInput ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`) console.log(`NumberInput ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
@@ -373,14 +383,17 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
} }
private createDropdownInput(paramName: string, label: string, values: Array<ElixFormsDropdownOption>, required: boolean = false): JSX.Element { private createDropdownInput(paramName: string, label: string, values: Array<ElixFormsDropdownOption>, required: boolean = false): JSX.Element {
const selectedValue = QueryParamHelper.getOptionFromQuery(paramName); const queryValue = QueryParamHelper.getOptionFromQuery(paramName);
const currentValue = this.state.formData[paramName] !== undefined
? this.state.formData[paramName]
: (queryValue?.toString() ?? '');
const options: FluentUI.IDropdownOption[] = []; const options: FluentUI.IDropdownOption[] = [];
values.forEach(entry => { values.forEach(entry => {
const id = `${paramName}_${entry.value}`;
options.push( options.push(
{ {
key: id, key: entry.value.toString(),
text: entry.label text: entry.label
} }
); );
@@ -388,19 +401,25 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
return new ElixFormsElement( return new ElixFormsElement(
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>, <FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
<FluentUI.Dropdown <>
id={paramName} <FluentUI.Dropdown
options={options} id={paramName}
selectedKey={selectedValue?.toString()} options={options}
placeholder='---' selectedKey={currentValue}
required={required} placeholder='---'
className='isiportalPartialAdminFormFieldSelect' required={required}
onChange={(event, value) => { className='isiportalPartialAdminFormFieldSelect'
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () => onChange={(event, option) => {
console.log(`Dropdown ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`) if (option) {
); const value = option.key.toString();
}} this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
/> console.log(`Dropdown ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
);
}
}}
/>
<input type="hidden" name={paramName} id={paramName + '_hidden'} value={currentValue} />
</>
).render(); ).render();
} }
@@ -10,7 +10,7 @@ export interface IElixFormsComponentProperties {
additionalFieldsJson?: string; additionalFieldsJson?: string;
// Layout Properties // Layout Properties
moduleTitle?: string; headerTitle?: string;
pageTitle?: string; pageTitle?: string;
pageDescription?: string; pageDescription?: string;
heroImageSrc?: string; heroImageSrc?: string;
@@ -43,7 +43,7 @@ export default class SceltaCarrieraComponent extends ElixFormsComponentAbstract
); );
} }
protected override renderExtraContent(): JSX.Element { protected override renderExtraContentPost(): JSX.Element {
return <p>Altre cose</p>; return <p>Altre cose</p>;
} }
} }