Roundabout
Ce composant se comporte comme une boucle avec une page carrefour qui permet de sauter à n'importe quelle itération.
- components, tableau contenant les composants enfant à cette boucle
- iterations, expression VTL permettant de calculer le nombre d'itérations
- expressions, un objet contenant les différents libellés à afficher pour chaque élément du rond point
- unnecessary, condition d'affichage du libellé "Non concerné" sur le bouton (expression VTL)
- complete, condition d'affichage du libellé "Complété" sur le bouton (expression VTL)
- partial, condition d'affichage du libellé "Modifier" sur le bouton (expression VTL)
- label, libellé à afficher au dessus du bouton (expression VTL)
- Source
- Data
{
"maxPage": "4",
"components": [
{
"id": "how",
"componentType": "InputNumber",
"mandatory": false,
"page": "1",
"min": 1,
"max": 10,
"decimals": 0,
"label": {
"value": "\"Combien de personnes vivent habituellement à votre adresse ?\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"response": {
"name": "NB_HAB"
}
},
{
"id": "loop",
"componentType": "Loop",
"page": "2",
"depth": 1,
"paginatedLoop": false,
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"loopDependencies": [
"NHAB"
],
"lines": {
"min": {
"value": "NB_HAB",
"type": "VTL"
},
"max": {
"value": "NB_HAB",
"type": "VTL"
}
},
"components": [
{
"id": "prenom",
"componentType": "Input",
"mandatory": false,
"maxLength": 20,
"label": {
"value": "\"Prénom\"))",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"response": {
"name": "PRENOMS"
}
},
{
"id": "age",
"componentType": "InputNumber",
"maxLength": 3,
"label": {
"value": "\"Age\"))",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"response": {
"name": "AGE"
}
}
]
},
{
"id": "roundabout",
"componentType": "Roundabout",
"page": "3",
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"iterations": {
"value": "NB_HAB",
"type": "VTL"
},
"label": {
"value": "\"Libellé du rondpoint\"",
"type": "VTL"
},
"locked": true,
"progressVariable": "PROGRESS",
"item": {
"label": {
"value": "\"Questions de \" || PRENOMS",
"type": "VTL"
},
"description": {
"value": "if AGE > 18 then \"Aller aux question destinées à \" || PRENOMS else PRENOMS || \" n'est pas majeur, il/elle n'a pas à répondre aux questions\"",
"type": "VTL"
},
"disabled": {
"value": "AGE < 18",
"type": "VTL"
}
},
"controls": [],
"components": [
{
"id": "radio",
"componentType": "Radio",
"mandatory": false,
"page": "3.1",
"label": {
"value": "\"Connaissez-vous le recensement de la population ?\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"options": [
{
"value": "1",
"label": {
"value": "\"oui\"",
"type": "VTL|MD"
}
},
{
"value": "2",
"label": {
"value": "\"non\"",
"type": "VTL|MD"
}
}
],
"response": {
"name": "KNOWREC"
}
},
{
"id": "jsygk7m7",
"componentType": "Subsequence",
"page": "3.2",
"label": {
"value": "\"Deuxième page de questions pour \"|| PRENOMS",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
}
},
{
"id": "sexe",
"componentType": "Radio",
"page": "3.2",
"label": {
"value": "\"Sexe\"",
"type": "VTL"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"options": [
{
"value": "1",
"label": {
"value": "\"Homme\"",
"type": "VTL|MD"
}
},
{
"value": "2",
"label": {
"value": "\"Femme\"",
"type": "VTL|MD"
}
}
],
"response": {
"name": "SEXE"
}
},
{
"id": "jsygk7m7",
"componentType": "Subsequence",
"page": "3.3",
"label": {
"value": "\"Troisième page de questions \" || PRENOMS",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
}
},
{
"id": "kmno1n7m",
"componentType": "Input",
"maxLength": 30,
"page": "3.3",
"label": {
"value": "\"Dites quelque chose.\"))",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"response": {
"name": "SOMETHING"
}
}
]
},
{
"id": "seq",
"componentType": "Sequence",
"label": {
"value": "\"Merci !\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "4"
}
],
"variables": [
{
"variableType": "COLLECTED",
"name": "NB_HAB",
"values": {
"PREVIOUS": null,
"COLLECTED": 2,
"FORCED": null,
"EDITED": null,
"INPUTTED": null
}
},
{
"variableType": "COLLECTED",
"name": "SOMETHING",
"values": {
"PREVIOUS": [],
"COLLECTED": [],
"FORCED": [],
"EDITED": [],
"INPUTTED": []
}
},
{
"variableType": "COLLECTED",
"name": "AGE",
"values": {
"PREVIOUS": null,
"COLLECTED": [
15,
15
],
"FORCED": null,
"EDITED": null,
"INPUTTED": null
}
},
{
"variableType": "COLLECTED",
"name": "SEXE",
"values": {
"PREVIOUS": [],
"COLLECTED": [],
"FORCED": [],
"EDITED": [],
"INPUTTED": []
}
},
{
"variableType": "COLLECTED",
"name": "PRENOMS",
"values": {
"PREVIOUS": null,
"COLLECTED": [
"Fanny",
"Ines"
],
"FORCED": null,
"EDITED": null,
"INPUTTED": null
}
},
{
"variableType": "COLLECTED",
"name": "KNOWREC",
"values": {
"PREVIOUS": [],
"COLLECTED": [],
"FORCED": [],
"EDITED": [],
"INPUTTED": []
}
},
{
"variableType": "COLLECTED",
"name": "PROGRESS",
"values": {
"PREVIOUS": [],
"COLLECTED": [],
"FORCED": [],
"EDITED": [],
"INPUTTED": []
}
},
{
"variableType": "CALCULATED",
"name": "PRENOMREF",
"expression": {
"value": "first_value(PRENOMS over())",
"type": "VTL"
},
"bindingDependencies": [
"PRENOMS"
],
"inFilter": "true"
},
{
"variableType": "CALCULATED",
"name": "COMPLETE",
"expression": {
"value": "not(isnull(KNOWREC)) and not(isnull(SEXE)) and not(isnull(SOMETHING))",
"type": "VTL"
},
"bindingDependencies": [
"KNOWREC",
"SEXE",
"SOMETHING"
],
"shapeFrom": "PRENOMS",
"inFilter": "true"
},
{
"variableType": "CALCULATED",
"name": "PARTIAL",
"expression": {
"value": "not(isnull(KNOWREC)) or not(isnull(SEXE)) or not(isnull(SOMETHING))",
"type": "VTL"
},
"bindingDependencies": [
"KNOWREC",
"SEXE",
"SOMETHING"
],
"shapeFrom": "PRENOMS",
"inFilter": "true"
}
],
"resizing": {
"NB_HAB": {
"size": "NB_HAB",
"variables": [
"PRENOMS",
"AGE",
"SEXE",
"SOMETHING",
"DATNAIS"
]
}
}
}
{}
- Code
- Rendu
import {
type LunaticData,
type LunaticSource,
type LunaticState,
useLunatic,
LunaticComponents,
ModalControls,
} from '@inseefr/lunatic';
import { useState } from 'react';
type Props = {
source: LunaticSource;
data: LunaticData;
options?: {initialPage?: LunaticState['pageTag']},
};
export function FormRendererWithNavigation({ source, data, options }: Props) {
const {
getComponents,
isLastPage,
isFirstPage,
goPreviousPage,
goNextPage,
Provider,
compileControls,
} = useLunatic(source, data, {
initialPage: '1' as LunaticState['pageTag'],
...options
});
// Les contrôles doivent être vérifiés manuellement
const [errors, setErrors] = useState<ReturnType<typeof compileControls>>();
const handleNext = () => {
const currentPageErrors = compileControls();
if (currentPageErrors.currentErrors) {
setErrors(currentPageErrors);
} else {
goNextPage();
}
};
const forceNext = () => {
setErrors(undefined);
goNextPage();
};
const closeModal = () => {
setErrors(undefined);
};
return (
<div>
<Provider>
<LunaticComponents
components={getComponents()}
componentProps={() => ({
errors: errors?.currentErrors,
})}
/>
</Provider>
<div style={{ marginTop: '.7rem', display: 'flex', gap: '.2rem' }}>
<button className="button button--primary" disabled={isFirstPage} onClick={goPreviousPage}>
Précédent
</button>
<button className="button button--primary" disabled={isLastPage} onClick={handleNext}>
Suivant
</button>
</div>
{errors && (
<ModalControls
errors={errors.currentErrors}
goNext={forceNext}
onClose={closeModal}
isCritical={errors.isCritical}
/>
)}
</div>
);
}
Loading...
Navigation
Si le rond-point ne contient qu'un seul élément, il se comporte alors comme une boucle paginée. En revanche s'il a plus d'un élément certains comportement changent par rapport à une boucle paginée.
- Lors de l'arrivée sur le rond-point, on n'est pas redirigé automatiquement sur la première itération. On propose à l'utilisateur de choisir l'itération sur laquelle il souhaite aller.
- À la fin d'une séquence, on n'est pas amené à l'itération suivante, on revient à la page d'accueil du rond-point.
Ce comportement fonctionne dans les 2 sens de navigation.