Modèles d'attributs : définitions des champs du formulaire
Structure d'un schéma
{
"type":"object",
"title":"Demande d'adhésion",
"description":"Demande d'adhésion",
"$schema":"http://json-schema.org/draft-07/schema",
"properties":{
attributs...
}
}
Description d'un attribut
Nom du champ
Bloc plié par défaut
La propriété collapsable n'a effet que sur les objets (pas d'effet sur l'objet racine)
Si il y a un cache pour l'état du formulaire, cette directive n'est pas prioritaire sauf si il y a des champs requis (un cache composant est mis en place pour la qualification d'entrée)
Champ requis
Doit être mentionné dans son parent
Position du champ à l'affichage
Anomalie répertoriée #33043 : comportement inattendu avec les dizaines (ex : 20 est interprété comme 2)
Champ plus petit
Symbole en suffixe du champ
Uniquement pour un champ de type 'number'
Comportement pour la recherche
-
partial: valeur partielle (%search%) -
exact: valeur exacte -
date: pour les dates -
numeric: pour les nombres
Validation de format (front)
Expressions régulières utilisées
À noter que
regexest aussi utilisé quandtypeeststringcoté validation back
Ajout d'un mask pour un champ
-
Pour appliquer un mask de formatage dans un champs, on opte pour le syntaxe indiqué à droite
-
Pour plus de documentation sur les formats et les paramètres du mask : https://github.com/JsDaddy/ngx-mask#examples
"field": {
...
"view": {
...,
"mask": {
"mask": "00 00 00 00 00 00",
"showMaskTyped": true
},
},
...
}
Cacher un champ
Cas d'usage: Un champ
user_managerrécupère un objet d'un référentiel:
displayName: Jean DUPONTidentifier: j.dupontLe champs affiche le
displayNamemais doit stocker sont identifiant dans un autre champuser_manager_id(mais qui est technique et pas intéressant pour l'utilisateur).
Afficher une icone de champ auto-évalué
![]()
Cas d'usage: Un champ est rempli coté serveur et n'a pas pour vocation d'interagir avec l'utilisateur
Il est préférable dans ce cas de le mettre en
readOnly.
Valeur par défaut
Permet de proposer une valeur par défaut pour le champ en cour à la création d'un objet.
La valeur dépendra de type de champ (property / field).
Dictionnaire d'attributs
Créer un schéma de dictionnaire d'attributs permet de réutiliser les attributs pour d'autres schémas.
Structure d'un schéma dictionnaire
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Dictionnaire d'attributs",
"type": "object",
"$defs": {
"contact": {
...
}
}
}
Appel au dictionnaire
"myBloc": {
"title": "Mon bloc",
"type": "object",
"properties": {
"contact": {
"$ref": "http://<{url.host}>/schemas/<strval(@schema_dictionary->id)>/content#/\$defs/contact"
},
}
}
Conditionner le caractère obligatoire de deux champs : anyOf
Cas d'usage : Un des deux champ
phonedoit être remplis dans un formulaire
"myBloc": {
"title": "Mon bloc",
"type": "object",
"anyOf": [
{
"required": [
"phone"
]
},
{
"required": [
"email"
]
}
],
"properties": {
"phone": {
...
},
"email": {
...
}
}
}
Conditionner l'apparition d'un champ par par rapport à un autre
Deux syntaxes sont supportées pour le moment :
- If .. then simple :
Cas d'usage le plus simple avec une seule condition:
- Je sélectionne
vegetarienpour le champregime, le champlegumesapparaît
"properties":{
"regime":{
"title":"Régime",
"type":"string",
"enum":[
"vegetarien",
"carnivore"
],
"view":{
"type":"input-radio"
},
"filterNode":"exact"
}
},
"if": {
"properties": { "regime": { "const": "vegetarien" } }
},
"then": {
"properties": {
"legumes":{
"title":"Légumes",
"type":"array",
"items": {
"type":"string",
"enum":[
"Concombre",
"Carotte"
]
},
"view":{
"type":"input-checkbox"
},
"filterNode":"exact"
}
}
}
- allOff avec des condition (au moins deux conditions différentes):
Cas d'usage :
- Je sélectionne
vegetarienpour le champregime, le champlegumesapparaît- Je sélectionne
carnivorepour le champregime, le champviandesapparaît
Ce qui nous donne:
"properties": {
"regime": {
"title":"Régime",
"type":"string",
"enum": [
"vegetarien",
"carnivore"
],
"view": {
"type":"input-radio"
},
"filterNode":"exact"
}
}
"allOf" : [
{
"if": {
"properties": { "regime": { "const": "vegetarien" } }
},
"then": {
"properties": {
"legumes":{
"title":"Légumes",
"type":"array",
"items": {
"type":"string",
"enum":[
"Concombre",
"Carotte"
]
},
"view":{
"type":"input-checkbox"
},
"filterNode":"exact"
}
}
}
},
{
"if": {
"properties": { "regime": { "const": "carnivore" } }
},
"then": {
"properties": {
"viandes":{
"title":"Viandes",
"type":"array",
"items": {
"type":"string",
"enum":[
"Poulet",
"Porc"
]
},
"view":{
"type":"input-checkbox"
},
"filterNode":"exact"
}
}
}
}
]
Référence externe
Si le champ est issu d'un référentiel externe, il faut décrire le service auquel faire appel ainsi que la stratégie d'écriture à mettre en place.\ Ci-dessous un exemple d'un code postal issu d'un référentiel externe :
"codePostal": {
"type": "string",
"external": {
"service": "matricule-service",
"bindings": [
{
"attribute": "nom_commune",
"serviceAttribute": "nom_commune",
"initOnField": true,
"searchProperty": "nom_commune",
"searchType": "partial",
"limit": 15,
"sortField": "nom_commune",
"sort": "asc",
"viewFormat": "{nom_commune} - {Code_postal}" // serviceAttributes
}
]
},
"title": "Code Postal",
"view": {
"type": "input-autocomplete",
"size": "small-block"
},
"position": 6,
"pseudoFormat": "postcode",
"filterNode": "partial"
}
Référence interne
Si le champ est issu d'un référentiel interne, il faut décrire le service auquel faire appel à la racine du modèle.
ex :
- Le champ
nom_completdéfini dans le blocinformationset le champsidentifiant_utilisateurdans le blocautres - Le champ
nick_namedéfini dans le blocinformationset le champ dans les attributsnickNamedans l'attributrootSchemaUseret le blockinformation
attributesModel_user:
...,
"internals": [
{
"service": "user",
"url": "users",
"bindings": [
{
"attribute": "informations.nom_complet",
"initOnField": true,
"serviceAttribute": "displayName",
"searchProperty": "displayName",
"searchType": "partial",
"limit": 15,
"sortField": "displayName",
"sort": "asc",
"viewFormat": "{displayName}"
},
{
"attribute": "informations.identifiant_utilisateur",
"serviceAttribute": "identifier",
"searchProperty": "identifier",
"isValidationKey": true,
},
{
"attribute": "autres.nick_name",
"serviceAttribute": "attributes:rootSchemaUser.information.nickName"
}
]
}
],
content: {
...
},
...
}
Pour plus d'information technique : https://labs.maarch.org/maarch/mdf-api-full/-/wikis/Reference/InternalService/R%C3%A9ferentiel-interne#principe
Interfaces disponibles
| Interface | type jsonchema |
filterNode jsonchema |
Gère l'attribut format jsonchema ? |
Gère le référence externe ? | Gère le référence interne ? | Gère l'attribut pattern jsonchema ? |
Gère l'attribut minLength jsonchema ? |
Gère l'attribut maxLength jsonchema ? |
|---|---|---|---|---|---|---|---|---|
| Bloc (section) | object |
|||||||
| Liste déroulante (à choix unique) | enum |
exact |
||||||
| Liste déroulante (à choix multiple) | enum |
exact |
||||||
| Champ autocompletion | string |
exact / partial |
||||||
| Champ texte | string |
exact / partial |
||||||
| Champ textearea | string |
exact / partial |
||||||
| Champ numérique | number / integer |
numeric |
||||||
| Champ date | string |
date |
date) |
|||||
| Champ radio (à choix unique) | enum |
exact |
||||||
| Champ case à cocher (à choix multiple) | array |
exact |
||||||
| Champ toggle | boolean |
exact |
||||||
| Champ image | string |
exact |
Exemples JSONschema
Bloc (section)
{
"title":"Adresse",
"description":"Adresse",
"type":"object",
"position": 1,
"properties": { // others attributes... }
}
Liste déroulante (à choix unique)
"sexe": {
"title": "Sexe",
"enum": [ "Féminin", "Masculin" ],
"type": "string",
"view": {
"type": "input-select",
},
"pattern": "^(Féminin|Masculin)$",
"position": 1,
"filterNode": "exact"
}
Liste déroulante (à choix multiple)
Pour un référentiel, l'attribut
loadOnInitest requis car il faut la liste complète pour que le champ fonctionne correctement.
"sexe": {
"title": "Sexe",
"enum": [ "Féminin", "Masculin" ],
"type": "array",
"view": {
"type": "input-select-multiple",
},
"position": 1,
"filterNode": "exact"
}
Champ auto complété
"color": {
"title": "Couleur",
"enum": [ "Bleu", "Blanc", "Rouge", ],
"type": "string",
"view": {
"type": "input-autocomplete"
},
"position": 1,
"filterNode": "partial"
}
Champ texte
"nom": {
"title": "Nom",
"position": 1,
"type": "string",
"view": {
"type": "input-text"
},
"filterNode": "partial"
}
Champ texte à valeurs multiples
minItems,maxItems,copySeparatoretuniqueItemssont facultatifs.
copySeparatorpermet de définir le caractère utilisé pour l'ajout automatique lors d'une copie (ex: liste d'emails en format scv séparé par un;.Les données sont automatiquement triées par ordre alphabétique.
"recipients": {
"title": "Destinataires",
"position": 1,
"type": "array",
"minItems": 2,
"maxItems": 5,
"uniqueItems": true,
"items": {
"type": "string"
},
"view": {
"type": "input-text-multiple",
"copySeparator": ";"
},
"filterNode": "partial"
}
Champ zone de texte
Peut avoir un attribut
nbLineToShowpour définir le nombre de lignes affichées dans le champ avant scroll. Si pas d'attribut, le champ s'adapte à l'entièreté du texte.Peut être
2,3,10,15,20
"story": {
"title": "Récit",
"position": 1,
"type": "string",
"view": {
"type": "input-textarea",
"nbLineToShow": 10
},
"filterNode": "partial"
}
Champ numérique (entiers)
Valeur de
1à10accepté dans cet exempleEnlever
minimumetmaximumsi non limité
"age": {
"title": "Age",
"position": 1,
"type": "integer",
"minimum": 1,
"maximum": 10,
"pattern": '^((-?[1-9])\d*)$',
"view": {
"type": "input-number"
},
"filterNode": "numeric"
}
Champ décimal
Les valeurs sont affichés avec
,mais la valeur stockée est avec.Ex :
20,4=>20.4
"nom": {
"title": "Montant HT",
"position": 1,
"type": "number",
"pattern": "^\d*,?\d*$",
"view": {
"type": "input-number",
"mask": {
"mask":"separator.2",
"suffix": " €"
}
},
"filterNode": "numeric"
}
Champ date
une date minimum peut être défini ex:
view.minDate: "2025-01-01"(formatYYYY-MMM-DD)une date maximum peut être défini ex :
view.maxDate: "2025-01-01"(formatYYYY-MMM-DD)La valeur
todaypeut être utilisé pour définir la date du jourATTTENTION! Ceci n'est pas soumis à validation coté API, ceci est purement niveau interface
"birthDate": {
"title": "Date de naissance",
"position": 1,
"type": "string",
"format": "date",
"view": {
"type": "input-date",
"minDate": "1970-01-01",
"maxDate": "today",
"mask": {
"mask":"d0/M0/0000",
"showMaskTyped": true
}
},
"filterNode": "date"
}
Champ radio (à choix unique)
"sexe": {
"title": "Sexe",
"enum": [ "Féminin", "Masculin" ],
"type": "string",
"view": {
"type": "input-radio"
},
"pattern": "^(Féminin|Masculin)$",
"position": 1,
"filterNode": "exact"
}
Champ case à cocher (à choix multiple)
"menu": {
"title": "Choix du menu",
"type": "array",
"items": {
"type": "string",
"enum": [ "Entrée", "Plat", "Dessert", "Boisson" ]
},
"view": {
"type": "input-checkbox"
},
"filterNode": "exact"
}
Champ toggle
"urgence": {
"title": "Urgent",
"type": "boolean",
"default": false,
"view": {
"type": "input-toggle"
},
"filterNode": "exact"
},