[{"data":1,"prerenderedAt":695},["ShallowReactive",2],{"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futilisation-des-grilles-et-formulaires":3,"section:\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futilisation-des-grilles-et-formulaires":694},{"id":4,"title":5,"body":6,"description":680,"extension":681,"meta":682,"navigation":167,"path":690,"seo":691,"stem":692,"__hash__":693},"docs\u002F2.next\u002F3.dodock\u002F10.developpeurs\u002F03.composants-ui\u002Futilisation-des-grilles-et-formulaires.md","Utilisation avancée des grilles et formulaires",{"type":7,"value":8,"toc":675},"minimark",[9,13,23,28,31,81,90,94,428,437,489,506,523,530,573,576,580,630,643,657,671],[10,11,5],"h1",{"id":12},"utilisation-avancée-des-grilles-et-formulaires",[14,15,16,17,22],"p",{},"Cette page concerne les formulaires Vue construits avec ",[18,19,21],"a",{"href":20},"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Fform-layout","FormLayout",". Elle explique comment votre application reçoit les modifications de l'utilisateur.",[24,25,27],"h2",{"id":26},"valeur-en-direct-et-validation","Valeur en direct et validation",[14,29,30],{},"Un champ transmet sa valeur de deux façons :",[32,33,34,50],"table",{},[35,36,37],"thead",{},[38,39,40,44,47],"tr",{},[41,42,43],"th",{},"Signal",[41,45,46],{},"Moment",[41,48,49],{},"Usage",[51,52,53,70],"tbody",{},[38,54,55,59,62],{},[56,57,58],"td",{},"Valeur en direct",[56,60,61],{},"À chaque frappe ou choix",[56,63,64,65,69],{},"Le document (",[66,67,68],"code",{},"v-model:doc",") est toujours à jour.",[38,71,72,75,78],{},[56,73,74],{},"Validation (commit)",[56,76,77],{},"À la sortie d'un champ de saisie, au choix dans un sélecteur",[56,79,80],{},"Lancer un script : recalcul, appel serveur, contrôle.",[14,82,83,85,86,89],{},[66,84,21],{}," n'émet pas les validations lui-même. Elles passent par un canal que votre application fournit avec la clé ",[66,87,88],{},"CommitKey",".",[24,91,93],{"id":92},"fournir-le-canal-de-validation","Fournir le canal de validation",[95,96,101],"pre",{"className":97,"code":98,"language":99,"meta":100,"style":100},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { provide } from \"vue\";\nimport { CommitKey } from \"@framework\u002Fui\u002FFormLayout\";\n\nprovide(CommitKey, {\n    pending(fieldname, value, row) {\n        \u002F\u002F saisie en cours, pas encore validée : à valider avant l'enregistrement\n    },\n    commit(fieldname, value, row) {\n        if (row) {\n            console.log(`Ligne ${row.key} du tableau ${row.parentfield} : ${fieldname} = ${value}`);\n        } else {\n            console.log(`${fieldname} = ${value}`);\n        }\n    },\n    rowChanged(row, change) {\n        \u002F\u002F change vaut \"add\" ou \"remove\"\n    },\n});\n","js","",[66,102,103,139,162,169,185,214,221,227,249,267,337,348,378,384,389,408,414,419],{"__ignoreMap":100},[104,105,108,112,116,120,123,126,129,133,136],"span",{"class":106,"line":107},"line",1,[104,109,111],{"class":110},"s7zQu","import",[104,113,115],{"class":114},"sMK4o"," {",[104,117,119],{"class":118},"sTEyZ"," provide",[104,121,122],{"class":114}," }",[104,124,125],{"class":110}," from",[104,127,128],{"class":114}," \"",[104,130,132],{"class":131},"sfazB","vue",[104,134,135],{"class":114},"\"",[104,137,138],{"class":114},";\n",[104,140,142,144,146,149,151,153,155,158,160],{"class":106,"line":141},2,[104,143,111],{"class":110},[104,145,115],{"class":114},[104,147,148],{"class":118}," CommitKey",[104,150,122],{"class":114},[104,152,125],{"class":110},[104,154,128],{"class":114},[104,156,157],{"class":131},"@framework\u002Fui\u002FFormLayout",[104,159,135],{"class":114},[104,161,138],{"class":114},[104,163,165],{"class":106,"line":164},3,[104,166,168],{"emptyLinePlaceholder":167},true,"\n",[104,170,172,176,179,182],{"class":106,"line":171},4,[104,173,175],{"class":174},"s2Zo4","provide",[104,177,178],{"class":118},"(CommitKey",[104,180,181],{"class":114},",",[104,183,184],{"class":114}," {\n",[104,186,188,192,195,199,201,204,206,209,212],{"class":106,"line":187},5,[104,189,191],{"class":190},"swJcz","    pending",[104,193,194],{"class":114},"(",[104,196,198],{"class":197},"sHdIc","fieldname",[104,200,181],{"class":114},[104,202,203],{"class":197}," value",[104,205,181],{"class":114},[104,207,208],{"class":197}," row",[104,210,211],{"class":114},")",[104,213,184],{"class":114},[104,215,217],{"class":106,"line":216},6,[104,218,220],{"class":219},"sHwdD","        \u002F\u002F saisie en cours, pas encore validée : à valider avant l'enregistrement\n",[104,222,224],{"class":106,"line":223},7,[104,225,226],{"class":114},"    },\n",[104,228,230,233,235,237,239,241,243,245,247],{"class":106,"line":229},8,[104,231,232],{"class":190},"    commit",[104,234,194],{"class":114},[104,236,198],{"class":197},[104,238,181],{"class":114},[104,240,203],{"class":197},[104,242,181],{"class":114},[104,244,208],{"class":197},[104,246,211],{"class":114},[104,248,184],{"class":114},[104,250,252,255,258,261,264],{"class":106,"line":251},9,[104,253,254],{"class":110},"        if",[104,256,257],{"class":190}," (",[104,259,260],{"class":118},"row",[104,262,263],{"class":190},") ",[104,265,266],{"class":114},"{\n",[104,268,270,273,275,278,280,283,286,289,291,293,296,299,302,304,306,308,311,313,316,318,320,322,325,327,330,333,335],{"class":106,"line":269},10,[104,271,272],{"class":118},"            console",[104,274,89],{"class":114},[104,276,277],{"class":174},"log",[104,279,194],{"class":190},[104,281,282],{"class":114},"`",[104,284,285],{"class":131},"Ligne ",[104,287,288],{"class":114},"${",[104,290,260],{"class":118},[104,292,89],{"class":114},[104,294,295],{"class":118},"key",[104,297,298],{"class":114},"}",[104,300,301],{"class":131}," du tableau ",[104,303,288],{"class":114},[104,305,260],{"class":118},[104,307,89],{"class":114},[104,309,310],{"class":118},"parentfield",[104,312,298],{"class":114},[104,314,315],{"class":131}," : ",[104,317,288],{"class":114},[104,319,198],{"class":118},[104,321,298],{"class":114},[104,323,324],{"class":131}," = ",[104,326,288],{"class":114},[104,328,329],{"class":118},"value",[104,331,332],{"class":114},"}`",[104,334,211],{"class":190},[104,336,138],{"class":114},[104,338,340,343,346],{"class":106,"line":339},11,[104,341,342],{"class":114},"        }",[104,344,345],{"class":110}," else",[104,347,184],{"class":114},[104,349,351,353,355,357,359,362,364,366,368,370,372,374,376],{"class":106,"line":350},12,[104,352,272],{"class":118},[104,354,89],{"class":114},[104,356,277],{"class":174},[104,358,194],{"class":190},[104,360,361],{"class":114},"`${",[104,363,198],{"class":118},[104,365,298],{"class":114},[104,367,324],{"class":131},[104,369,288],{"class":114},[104,371,329],{"class":118},[104,373,332],{"class":114},[104,375,211],{"class":190},[104,377,138],{"class":114},[104,379,381],{"class":106,"line":380},13,[104,382,383],{"class":114},"        }\n",[104,385,387],{"class":106,"line":386},14,[104,388,226],{"class":114},[104,390,392,395,397,399,401,404,406],{"class":106,"line":391},15,[104,393,394],{"class":190},"    rowChanged",[104,396,194],{"class":114},[104,398,260],{"class":197},[104,400,181],{"class":114},[104,402,403],{"class":197}," change",[104,405,211],{"class":114},[104,407,184],{"class":114},[104,409,411],{"class":106,"line":410},16,[104,412,413],{"class":219},"        \u002F\u002F change vaut \"add\" ou \"remove\"\n",[104,415,417],{"class":106,"line":416},17,[104,418,226],{"class":114},[104,420,422,424,426],{"class":106,"line":421},18,[104,423,298],{"class":114},[104,425,211],{"class":118},[104,427,138],{"class":114},[14,429,430,431,433,434,436],{},"Appelez ",[66,432,175],{}," dans le composant qui contient ",[66,435,21],{},". Le canal a trois méthodes :",[32,438,439,449],{},[35,440,441],{},[38,442,443,446],{},[41,444,445],{},"Méthode",[41,447,448],{},"Appelée quand",[51,450,451,461,471],{},[38,452,453,458],{},[56,454,455],{},[66,456,457],{},"pending(fieldname, value, row?)",[56,459,460],{},"Une saisie est en cours et pas encore validée. Validez-la vous-même avant d'enregistrer, pour ne pas perdre le dernier script.",[38,462,463,468],{},[56,464,465],{},[66,466,467],{},"commit(fieldname, value, row?)",[56,469,470],{},"L'utilisateur valide une valeur.",[38,472,473,478],{},[56,474,475],{},[66,476,477],{},"rowChanged(row, change)",[56,479,480,481,484,485,488],{},"Une ligne est ajoutée (",[66,482,483],{},"\"add\"",") ou retirée (",[66,486,487],{},"\"remove\"",") d'un tableau.",[14,490,491,492,495,496,499,500,503,504,89],{},"Un nœud du schéma peut aussi porter ses propres écouteurs dans ",[66,493,494],{},"ui.on",", par exemple ",[66,497,498],{},"{ ui: { on: { change: (value) => … } } }",". Le champ émet ",[66,501,502],{},"change"," à sa validation. Voir ",[18,505,21],{"href":20},[14,507,508,509,511,512,515,516,519,520,522],{},"Pour une cellule de tableau, ",[66,510,260],{}," vaut ",[66,513,514],{},"{ parentfield, key }"," : le nom du champ ",[66,517,518],{},"Table"," et la clé de la ligne. Un champ ",[66,521,518],{}," ne valide jamais sous son propre nom : chaque cellule valide sous le nom de sa colonne. Il en va de même dans la boîte de dialogue d'édition d'une ligne.",[14,524,525,526,529],{},"Pour un formulaire sans script (boîte de création, démonstration), fournissez ",[66,527,528],{},"NO_COMMIT"," :",[95,531,533],{"className":97,"code":532,"language":99,"meta":100,"style":100},"import { CommitKey, NO_COMMIT } from \"@framework\u002Fui\u002FFormLayout\";\nprovide(CommitKey, NO_COMMIT);\n",[66,534,535,560],{"__ignoreMap":100},[104,536,537,539,541,543,545,548,550,552,554,556,558],{"class":106,"line":107},[104,538,111],{"class":110},[104,540,115],{"class":114},[104,542,148],{"class":118},[104,544,181],{"class":114},[104,546,547],{"class":118}," NO_COMMIT",[104,549,122],{"class":114},[104,551,125],{"class":110},[104,553,128],{"class":114},[104,555,157],{"class":131},[104,557,135],{"class":114},[104,559,138],{"class":114},[104,561,562,564,566,568,571],{"class":106,"line":141},[104,563,175],{"class":174},[104,565,178],{"class":118},[104,567,181],{"class":114},[104,569,570],{"class":118}," NO_COMMIT)",[104,572,138],{"class":114},[14,574,575],{},"Sans canal, les validations sont perdues. En développement, une erreur s'affiche dans la console.",[24,577,579],{"id":578},"identifier-une-ligne-de-tableau","Identifier une ligne de tableau",[32,581,582,595],{},[35,583,584],{},[38,585,586,589],{},[41,587,588],{},"Ligne",[41,590,591,592,211],{},"Clé (",[66,593,594],{},"row.key",[51,596,597,612],{},[38,598,599,602],{},[56,600,601],{},"Déjà enregistrée",[56,603,604,607,608,611],{},[66,605,606],{},"name:\u003Cname>",", à partir du ",[66,609,610],{},"name"," donné par le serveur",[38,613,614,617],{},[56,615,616],{},"Nouvelle",[56,618,619,622,623,626,627,89],{},[66,620,621],{},"new:\u003C__row_id>",". Le composant ajoute ",[66,624,625],{},"__row_id"," à la ligne, par exemple ",[66,628,629],{},"row-3",[14,631,632,633,635,636,639,640,642],{},"Le composant n'invente pas de ",[66,634,610],{}," pour une nouvelle ligne. ",[66,637,638],{},"frappe.client.save"," traite une ligne qui a un ",[66,641,610],{}," comme une ligne existante : l'insertion échouerait sans erreur.",[14,644,645,646,649,650,653,654,656],{},"Les deux types de clé sont séparés (",[66,647,648],{},"name:"," et ",[66,651,652],{},"new:","). Une ligne nommée ",[66,655,629],{}," par le serveur ne peut donc pas se confondre avec une nouvelle ligne.",[658,659,662],"callout",{"color":660,"icon":661},"info","i-lucide-info",[14,663,664,665,667,668,670],{},"Après le premier enregistrement, une nouvelle ligne reçoit son ",[66,666,610],{}," et perd ",[66,669,625],{},". Sa clé change : la ligne n'est plus sélectionnée. Ce comportement évite de supprimer la mauvaise ligne.",[672,673,674],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":100,"searchDepth":107,"depth":141,"links":676},[677,678,679],{"id":26,"depth":141,"text":27},{"id":92,"depth":141,"text":93},{"id":578,"depth":141,"text":579},"Recevoir les validations de saisie (commits) et les ajouts ou suppressions de lignes d'un formulaire FormLayout, et identifier les lignes de tableau pas encore enregistrées.","md",{"icon":683,"reviewed":167,"last_verified":684,"sources":685},"i-mdi-table-edit","2026-11-04",[686,687,688,689],"dodock@develop:ui\u002Fsrc\u002Fcomponents\u002FFields\u002Ftypes.ts","dodock@develop:ui\u002Fsrc\u002Fcomponents\u002FFields\u002FrowIdentity.ts","dodock@develop:ui\u002Fsrc\u002Fcomponents\u002FFormLayout\u002Findex.ts","dodock@develop:ui\u002Fsrc\u002Fcomponents\u002FFormLayout\u002FwarnMissingCommit.ts","\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futilisation-des-grilles-et-formulaires",{"title":5,"description":680},"2.next\u002F3.dodock\u002F10.developpeurs\u002F03.composants-ui\u002Futilisation-des-grilles-et-formulaires","N7uSRtikGTw7T2XLZFZZzxwT6g8_awd2WfC7d6JYbKo",{},1793871740827]