Loop
Le composant Loop (parfois appelé BlockForLoop) permet de créer une boucle permettant de poser une série de questions plusieurs fois (exemple: demander des informations sur plusieurs personnes).
- paginatedLoop, indique si la boucle doit être paginée ou non (defaut: false)
- components, tableau contenant les composants enfant à cette boucle
Boucle non paginée
Une boucle non paginée présentera l'ensemble des champs les uns à la suite des autres.
- lines, permet le contrôle sur le nombre de lignes (ajouter / supprimer)
- min, nombre minimal de lignes
- max, nombre maximal de lignes
- Source
- Data
{
"$schema": "../../../lunatic-schema.json",
"maxPage": "3",
"components": [
{
"id": "seq",
"componentType": "Sequence",
"label": {
"value": "\"Description des individus de votre logement\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "1"
},
{
"id": "loop-prenom",
"componentType": "Loop",
"label": {
"value": "\"Ajouter un individu\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"bindingDependencies": [
"PRENOM"
],
"lines": {
"min": {
"value": "1",
"type": "VTL"
},
"max": {
"value": "10",
"type": "VTL"
}
},
"page": "1",
"paginatedLoop": false,
"components": [
{
"componentType": "Input",
"label": {
"value": "\"Prénom\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"maxLength": 30,
"bindingDependencies": [
"PRENOM"
],
"id": "prenom",
"response": {
"name": "PRENOM"
}
},
{
"componentType": "InputNumber",
"label": {
"value": "\"Age\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"maxLength": 30,
"bindingDependencies": [
"AGE"
],
"id": "Age",
"response": {
"name": "AGE"
}
}
]
},
{
"id": "seq-end",
"componentType": "Sequence",
"label": {
"value": "\"End\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "2"
}
],
"variables": [
{
"variableType": "COLLECTED",
"name": "PRENOM",
"values": {
"PREVIOUS": [
null
],
"COLLECTED": [
null
],
"FORCED": [
null
],
"EDITED": [
null
],
"INPUTTED": [
null
]
}
},
{
"variableType": "COLLECTED",
"name": "AGE",
"values": {
"PREVIOUS": [
null
],
"COLLECTED": [
null
],
"FORCED": [
null
],
"EDITED": [
null
],
"INPUTTED": [
null
]
}
}
]
}
{}
- 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...
Boucle paginée
Une boucle paginée déclenchera un système de sous-navigation. Lorsque l'utilisateur arrive sur la page d'une boucle il sera automatiquement redirigé sur la première sous page.
- iterations, expression VTL permettant de calculer le nombre d'itérations à effectuer
- maxPage, numéro de la dernière sous page
info
Les composants dans le tableau components
devront avoir un numéro de page préfixé par la page
de cette boucle, ex: 3.1
)
- Source
- Data
{
"$schema": "../../../lunatic-schema.json",
"maxPage": "3",
"components": [
{
"id": "seq",
"componentType": "Sequence",
"label": {
"value": "\"Description des individus de votre logement\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "1"
},
{
"id": "loop-prenom",
"componentType": "Loop",
"label": {
"value": "\"Ajouter un individu\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"bindingDependencies": [
"PRENOM"
],
"lines": {
"min": {
"value": "1",
"type": "VTL"
},
"max": {
"value": "10",
"type": "VTL"
}
},
"page": "1",
"paginatedLoop": false,
"components": [
{
"componentType": "Input",
"label": {
"value": "\"Prénom\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"maxLength": 30,
"bindingDependencies": [
"PRENOM"
],
"id": "prenom",
"response": {
"name": "PRENOM"
}
}
]
},
{
"id": "loop",
"componentType": "Loop",
"loopDependencies": [
"PRENOM"
],
"iterations": {
"value": "count(PRENOM)",
"type": "VTL"
},
"page": "2",
"maxPage": "1",
"depth": 1,
"paginatedLoop": true,
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"components": [
{
"id": "age",
"label": {
"value": "PRENOM || \", quel est vôtre âge ?\"",
"type": "VTL"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "2.1",
"componentType": "InputNumber",
"min": 0,
"max": 120,
"decimals": 0,
"response": {
"name": "AGE"
}
}
]
},
{
"id": "seq-end",
"componentType": "Sequence",
"label": {
"value": "\"End\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"page": "3"
}
],
"resizing": {
"PRENOM": {
"size": "count(PRENOM)",
"variables": [
"AGE"
]
}
},
"variables": [
{
"variableType": "COLLECTED",
"name": "PRENOM",
"values": {
"PREVIOUS": null,
"COLLECTED": [
"John",
"Jane"
],
"FORCED": null,
"EDITED": null,
"INPUTTED": null
}
},
{
"variableType": "COLLECTED",
"name": "AGE",
"values": {
"PREVIOUS": null,
"COLLECTED": null,
"FORCED": null,
"EDITED": null,
"INPUTTED": null
}
}
]
}
{}
- 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...