PairwiseLinks
Le composant lien 2 à 2 permet de définir des relations bidirectionnelles entre les données.
- xAxisIterations, nombre d'éléments sur le premier axe
- yAxisIterations, nombre d'éléments sur le second axe
- components, liste des questions à poser pour chaque combinaison possible
- symLinks, définit la relation bidirectionnelle entre les données
symLinks
L'option symLinks va permettre d'indiquer la valeur inverse à une valeur sélectionnée. Si on prend l'exemple d'un sélect avec 3 valeurs
{
"symLinks": {
"LINKS": {
"époux": "époux",
"fils": "parent",
"parent": "fils"
}
}
}
De cette manière lorsqu'on indiquera que X est "fils" de Y, le système changera aussi la relation inverse pour indiquer que Y est "parent" de X.
xAxis et yAxis
Lorsque le pairwise est utilisé, 2 variables calculées vont agir de manière spéciale afin de pouvoir renvoyer les bonnes indications à l'utilisateur : xAxis et yAxis.
[
{
"variableType": "CALCULATED",
"name": "xAxis",
"expression": { "value": "PRENOM", "type": "VTL" },
"bindingDependencies": ["PRENOM"]
},
{
"variableType": "CALCULATED",
"name": "yAxis",
"expression": { "value": "PRENOM", "type": "VTL" },
"bindingDependencies": ["PRENOM"]
}
]
Si ces variables sont utilisées dans une expression d'un composant du pairwise, le système de calcul ira piocher l'élément au bon index.
{
"label": {
"value": "\"Qui est \" || yAxis || \" pour \" || xAxis || \" ?\"",
"type": "VTL|MD"
}
}
- Source
- Data
{
"maxPage": "5",
"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": "RosterForLoop",
"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",
"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": "age-loop",
"componentType": "Loop",
"paginatedLoop": true,
"iterations": {
"value": "count(PRENOM)",
"type": "VTL"
},
"page": "2",
"maxPage": "1",
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"loopDependencies": [
"PRENOM"
],
"components": [
{
"id": "age-quest",
"label": {
"value": "\"Âge de \" || PRENOM",
"type": "VTL|MD"
},
"conditionFilter": {
"type": "VTL",
"value": "true"
},
"componentType": "InputNumber",
"page": "2.1",
"response": {
"name": "AGE"
}
}
]
},
{
"id": "pairwise-links",
"componentType": "PairwiseLinks",
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"xAxisIterations": {
"value": "count(PRENOM)",
"type": "VTL"
},
"yAxisIterations": {
"value": "count(PRENOM)",
"type": "VTL"
},
"page": "3",
"symLinks": {
"LINKS": {
"1": "1",
"2": "3",
"3": "2",
"4": "4",
"5": "6",
"6": "5",
"7": "8",
"8": "7",
"9": "10",
"10": "9",
"11": "13",
"12": "12",
"13": "11",
"14": null,
"15": "15",
"16": "16",
"17": "17",
"18": "18"
}
},
"components": [
{
"componentType": "Dropdown",
"id": "dropdown-1",
"conditionFilter": {
"value": "xAxis <> yAxis",
"type": "VTL"
},
"label": {
"value": "\"Qui est \" || yAxis || \" pour \" || xAxis || \" ?\"",
"type": "VTL|MD"
},
"response": {
"name": "LINKS"
},
"options": [
{
"value": "1",
"label": {
"value": "\"Son conjoint, sa conjointe\"",
"type": "VTL"
}
},
{
"value": "2",
"label": {
"value": "\"Sa mère, son père\"",
"type": "VTL"
}
},
{
"value": "3",
"label": {
"value": "\"Sa fille, son fils\"",
"type": "VTL"
}
},
{
"value": "4",
"label": {
"value": "\"Sa soeur, son frère (y compris demi et quasi)\"",
"type": "VTL"
}
},
{
"value": "5",
"label": {
"value": "\"Sa belle-mère, son beau-père (conjoint.e d'un des parents)\"",
"type": "VTL"
}
},
{
"value": "6",
"label": {
"value": "\"L'enfant du conjoint (belle-fille, beau-fils)\"",
"type": "VTL"
}
},
{
"value": "7",
"label": {
"value": "\"Sa belle-mère, son beau-père (parent du conjoint)\"",
"type": "VTL"
}
},
{
"value": "8",
"label": {
"value": "\"Sa belle-fille, son beau-fils (conjoint.e d'un enfant)\"",
"type": "VTL"
}
},
{
"value": "9",
"label": {
"value": "\"Sa grand-mère, son grand-père\"",
"type": "VTL"
}
},
{
"value": "10",
"label": {
"value": "\"Sa petite-fille, petit-fils\"",
"type": "VTL"
}
},
{
"value": "11",
"label": {
"value": "\"Sa tante, son oncle\"",
"type": "VTL"
}
},
{
"value": "12",
"label": {
"value": "\"Sa cousine, son cousin\"",
"type": "VTL"
}
},
{
"value": "13",
"label": {
"value": "\"Sa nièce, son neveu\"",
"type": "VTL"
}
},
{
"value": "14",
"label": {
"value": "\"Un enfant placé en famille d'accueil\"",
"type": "VTL"
}
},
{
"value": "15",
"label": {
"value": "\"Sa belle-soeur, son beau-frère\"",
"type": "VTL"
}
},
{
"value": "16",
"label": {
"value": "\"Un autre lien familial\"",
"type": "VTL"
}
},
{
"value": "17",
"label": {
"value": "\"Un colocataire, sous-locataire\"",
"type": "VTL"
}
},
{
"value": "18",
"label": {
"value": "\"Autre lien (employé de maison, salarié logé, jeune au pair …)\"",
"type": "VTL"
}
}
]
},
{
"componentType": "Textarea",
"label": {
"value": "\"Pouvez-vous décrire le lien entre \" || xAxis || \" et \" || yAxis || \" ?\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "LINKS = \"17\"",
"type": "VTL"
},
"id": "other",
"response": {
"name": "OTHER"
}
}
]
},
{
"id": "pariwise-block",
"componentType": "Loop",
"paginatedLoop": true,
"iterations": {
"value": "count(PRENOM)",
"type": "VTL"
},
"page": "4",
"maxPage": "1",
"conditionFilter": {
"value": "true",
"type": "VTL"
},
"loopDependencies": [
"PRENOM"
],
"components": [
{
"componentType": "Textarea",
"page": "4.1",
"label": {
"value": "PRENOM || \", why do you live without your parents?\"",
"type": "VTL|MD"
},
"conditionFilter": {
"value": "\"3\" not_in LINKS and AGE < 18",
"type": "VTL"
},
"id": "why",
"response": {
"name": "WHY"
}
}
]
},
{
"componentType": "Sequence",
"label": {
"type": "VTL",
"value": "\"END\""
},
"page": "5",
"id": "end"
}
],
"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
]
}
},
{
"variableType": "COLLECTED",
"name": "LINKS",
"values": {
"PREVIOUS": [
[
null
]
],
"COLLECTED": [
[
null
]
],
"FORCED": [
[
null
]
],
"EDITED": [
[
null
]
],
"INPUTTED": [
[
null
]
]
}
},
{
"variableType": "COLLECTED",
"name": "OTHER",
"values": {
"PREVIOUS": [
[
null
]
],
"COLLECTED": [
[
null
]
],
"FORCED": [
[
null
]
],
"EDITED": [
[
null
]
],
"INPUTTED": [
[
null
]
]
}
},
{
"variableType": "COLLECTED",
"name": "WHY",
"values": {
"PREVIOUS": [
null
],
"COLLECTED": [
null
],
"FORCED": [
null
],
"EDITED": [
null
],
"INPUTTED": [
null
]
}
},
{
"variableType": "CALCULATED",
"name": "xAxis",
"expression": {
"value": "PRENOM",
"type": "VTL"
},
"bindingDependencies": [
"PRENOM"
],
"shapeFrom": "PRENOM",
"inFilter": "false"
},
{
"variableType": "CALCULATED",
"name": "yAxis",
"expression": {
"value": "PRENOM",
"type": "VTL"
},
"bindingDependencies": [
"PRENOM"
],
"shapeFrom": "PRENOM",
"inFilter": "false"
}
],
"resizing": {
"PRENOM": {
"sizeForLinksVariables": [
"count(PRENOM)",
"count(PRENOM)"
],
"linksVariables": [
"LINKS"
]
}
}
}
{
"COLLECTED": {
"PRENOM": {
"COLLECTED": [
"Maman",
"Papa",
"Fils"
]
},
"AGE": {
"COLLECTED": [
30,
29,
5
]
},
"LINKS": {
"COLLECTED": [
[
null
]
]
},
"OTHER": {
"COLLECTED": [
[
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>
);
}
Format des données
Les données sont sauvegardées sous forme d'un tableau à 2 dimensions
x \ y | Maman | Papa | Fils |
---|---|---|---|
Maman | |||
Papa | |||
Fils |
Si on souhaite indiquer la rélation Parent (valeur "2") et enfant (valeur "3"). En suivant la question "qui est Y pour X ?" le tableau sera complété de la manière suivante.
x \ y | Maman | Papa | Fils |
---|---|---|---|
Maman | 3 | ||
Papa | 3 | ||
Fils | 2 | 2 |
Ce qui donnera ce tableau en JavaScript
[
[null, null, "3" ],
[null, null, "3" ],
["2", "2", null]
]