[{"data":1,"prerenderedAt":568},["ShallowReactive",2],{"content-\u002Fdocs\u002Freading-the-form\u002Frecord":3},{"id":4,"title":5,"body":6,"description":550,"extension":551,"meta":552,"metaRows":553,"navigation":147,"path":563,"seo":564,"source":565,"stem":566,"__hash__":567},"docs\u002Fdocs\u002Freading-the-form\u002Frecord.md","record",{"type":7,"value":8,"toc":540},"minimark",[9,15,30,33,57,62,67,74,349,362,366,399,403,413,441,444,451,471,477,497,501,536],[10,11,12],"h1",{"id":5},[13,14,5],"code",{},[16,17,18],"blockquote",{},[19,20,21,22,25,26,29],"p",{},"One record, one FieldState per entry, keyed by the entry's own key. Iterate it with ",[13,23,24],{},"v-for=\"(field, key) in form.record(path)\""," and bind ",[13,27,28],{},":key=\"key\"",".",[31,32],"docs-meta-table",{},[19,34,35,38,39,46,47,49,50,56],{},[13,36,37],{},"form.record(path)"," is the iteration view over a record. Where ",[40,41,43],"a",{"href":42},"\u002Fdocs\u002Freading-the-form\u002Flist",[13,44,45],{},"list"," hands back an ordered array for an array path, ",[13,48,5],{}," hands back a keyed object for a record path: one ",[40,51,53],{"href":52},"\u002Fdocs\u002Freading-the-form\u002Ffields",[13,54,55],{},"FieldState"," per entry, under the entry's own key. Reach for it whenever the keys are the data, set at run time rather than declared in the schema.",[58,59],"docs-demo",{"label":60,"slug":61},"form.record Demo","form-record",[63,64,66],"h2",{"id":65},"iterating-a-record","Iterating a record",[19,68,69,70,73],{},"Declare the record on your schema, then iterate ",[13,71,72],{},"form.record"," by its key. The keys come from the form, so you render whatever entries exist without keeping a parallel list of your own:",[75,76,81],"pre",{"className":77,"code":78,"language":79,"meta":80,"style":80},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\n  import { useForm } from 'attaform\u002Fzod'\n  import { z } from 'zod'\n\n  const schema = z.object({\n    scoresByTeam: z.record(z.string(), z.number()),\n  })\n\n  const form = useForm({ schema })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-for=\"(field, key) in form.record('scoresByTeam')\" :key=\"key\">\n    \u003Clabel>{{ key }}\u003C\u002Flabel>\n    \u003Cinput v-register=\"form.register(`scoresByTeam.${key}`)\" \u002F>\n    \u003Cp v-if=\"field.showErrors\">{{ field.firstError?.message }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue","",[13,82,83,113,129,142,149,171,194,200,205,221,231,236,246,273,289,308,330,340],{"__ignoreMap":80},[84,85,88,92,96,100,103,106,110],"span",{"class":86,"line":87},"line",1,[84,89,91],{"class":90},"sVt8B","\u003C",[84,93,95],{"class":94},"s9eBZ","script",[84,97,99],{"class":98},"sScJk"," setup",[84,101,102],{"class":98}," lang",[84,104,105],{"class":90},"=",[84,107,109],{"class":108},"sZZnC","\"ts\"",[84,111,112],{"class":90},">\n",[84,114,116,120,123,126],{"class":86,"line":115},2,[84,117,119],{"class":118},"szBVR","  import",[84,121,122],{"class":90}," { useForm } ",[84,124,125],{"class":118},"from",[84,127,128],{"class":108}," 'attaform\u002Fzod'\n",[84,130,132,134,137,139],{"class":86,"line":131},3,[84,133,119],{"class":118},[84,135,136],{"class":90}," { z } ",[84,138,125],{"class":118},[84,140,141],{"class":108}," 'zod'\n",[84,143,145],{"class":86,"line":144},4,[84,146,148],{"emptyLinePlaceholder":147},true,"\n",[84,150,152,155,159,162,165,168],{"class":86,"line":151},5,[84,153,154],{"class":118},"  const",[84,156,158],{"class":157},"sj4cs"," schema",[84,160,161],{"class":118}," =",[84,163,164],{"class":90}," z.",[84,166,167],{"class":98},"object",[84,169,170],{"class":90},"({\n",[84,172,174,177,179,182,185,188,191],{"class":86,"line":173},6,[84,175,176],{"class":90},"    scoresByTeam: z.",[84,178,5],{"class":98},[84,180,181],{"class":90},"(z.",[84,183,184],{"class":98},"string",[84,186,187],{"class":90},"(), z.",[84,189,190],{"class":98},"number",[84,192,193],{"class":90},"()),\n",[84,195,197],{"class":86,"line":196},7,[84,198,199],{"class":90},"  })\n",[84,201,203],{"class":86,"line":202},8,[84,204,148],{"emptyLinePlaceholder":147},[84,206,208,210,213,215,218],{"class":86,"line":207},9,[84,209,154],{"class":118},[84,211,212],{"class":157}," form",[84,214,161],{"class":118},[84,216,217],{"class":98}," useForm",[84,219,220],{"class":90},"({ schema })\n",[84,222,224,227,229],{"class":86,"line":223},10,[84,225,226],{"class":90},"\u003C\u002F",[84,228,95],{"class":94},[84,230,112],{"class":90},[84,232,234],{"class":86,"line":233},11,[84,235,148],{"emptyLinePlaceholder":147},[84,237,239,241,244],{"class":86,"line":238},12,[84,240,91],{"class":90},[84,242,243],{"class":94},"template",[84,245,112],{"class":90},[84,247,249,252,255,258,260,263,266,268,271],{"class":86,"line":248},13,[84,250,251],{"class":90},"  \u003C",[84,253,254],{"class":94},"div",[84,256,257],{"class":98}," v-for",[84,259,105],{"class":90},[84,261,262],{"class":108},"\"(field, key) in form.record('scoresByTeam')\"",[84,264,265],{"class":98}," :key",[84,267,105],{"class":90},[84,269,270],{"class":108},"\"key\"",[84,272,112],{"class":90},[84,274,276,279,282,285,287],{"class":86,"line":275},14,[84,277,278],{"class":90},"    \u003C",[84,280,281],{"class":94},"label",[84,283,284],{"class":90},">{{ key }}\u003C\u002F",[84,286,281],{"class":94},[84,288,112],{"class":90},[84,290,292,294,297,300,302,305],{"class":86,"line":291},15,[84,293,278],{"class":90},[84,295,296],{"class":94},"input",[84,298,299],{"class":98}," v-register",[84,301,105],{"class":90},[84,303,304],{"class":108},"\"form.register(`scoresByTeam.${key}`)\"",[84,306,307],{"class":90}," \u002F>\n",[84,309,311,313,315,318,320,323,326,328],{"class":86,"line":310},16,[84,312,278],{"class":90},[84,314,19],{"class":94},[84,316,317],{"class":98}," v-if",[84,319,105],{"class":90},[84,321,322],{"class":108},"\"field.showErrors\"",[84,324,325],{"class":90},">{{ field.firstError?.message }}\u003C\u002F",[84,327,19],{"class":94},[84,329,112],{"class":90},[84,331,333,336,338],{"class":86,"line":332},17,[84,334,335],{"class":90},"  \u003C\u002F",[84,337,254],{"class":94},[84,339,112],{"class":90},[84,341,343,345,347],{"class":86,"line":342},18,[84,344,226],{"class":90},[84,346,243],{"class":94},[84,348,112],{"class":90},[19,350,351,353,354,357,358,361],{},[13,352,5],{}," is typed against every record path in the schema (a ",[13,355,356],{},"z.record(...)",", not a fixed-shape ",[13,359,360],{},"z.object({ ... })","), so the path autocompletes to records only, and each entry's type narrows to the record's value shape.",[63,363,365],{"id":364},"each-entry-is-a-live-fieldstate","Each entry is a live FieldState",[19,367,368,369,374,375,378,379,378,382,378,385,378,388,391,392,398],{},"Each value in the returned object is the same field state ",[40,370,371],{"href":52},[13,372,373],{},"fields"," exposes, so every read stays live as the user types. An entry carries the full surface: ",[13,376,377],{},"field.value",", ",[13,380,381],{},"field.errors",[13,383,384],{},"field.showErrors",[13,386,387],{},"field.firstError",[13,389,390],{},"field.touched",", and the rest. Binding still flows through ",[40,393,395],{"href":394},"\u002Fdocs\u002Fbinding-inputs\u002Fv-register",[13,396,397],{},"form.register"," with the entry path, which the key supplies.",[63,400,402],{"id":401},"growing-and-shrinking","Growing and shrinking",[19,404,405,406,412],{},"The returned object is frozen, a read-only view. A record carries its own keys, so you grow or shrink it through ",[40,407,409],{"href":408},"\u002Fdocs\u002Fwriting-and-mutating\u002Fset-value",[13,410,411],{},"setValue"," at an entry path. Write a key that isn't there yet and a new entry joins the view:",[75,414,418],{"className":415,"code":416,"language":417,"meta":80,"style":80},"language-ts shiki shiki-themes github-light github-dark","form.setValue('scoresByTeam.west', 0)\n","ts",[13,419,420],{"__ignoreMap":80},[84,421,422,425,427,430,433,435,438],{"class":86,"line":87},[84,423,424],{"class":90},"form.",[84,426,411],{"class":98},[84,428,429],{"class":90},"(",[84,431,432],{"class":108},"'scoresByTeam.west'",[84,434,378],{"class":90},[84,436,437],{"class":157},"0",[84,439,440],{"class":90},")\n",[19,442,443],{},"The existing entries keep their field states and their component instances; only the new row mounts. To drop an entry, write the record back without that key.",[63,445,447,450],{"id":446},"formfields-stays-the-aggregate",[13,448,449],{},"form.fields"," stays the aggregate",[19,452,453,456,457,378,460,463,464,467,468,470],{},[13,454,455],{},"form.fields('scoresByTeam')"," remains the single aggregated container for the whole record: one rolled-up FieldState whose ",[13,458,459],{},"errors",[13,461,462],{},"valid",", and ",[13,465,466],{},"touched"," summarize every entry at once. Reach for the aggregate when you want one verdict for the record, and for ",[13,469,5],{}," when you want an entry each.",[63,472,474,476],{"id":473},"list-is-the-array-counterpart",[13,475,45],{}," is the array counterpart",[19,478,479,480,484,485,487,488,490,491,493,494,496],{},"For an array, reach for ",[40,481,482],{"href":42},[13,483,45],{},", which returns an ordered FieldState array keyed by an allocated identity token that survives reorders. ",[13,486,5],{}," and ",[13,489,45],{}," split cleanly by path type: a record reads through ",[13,492,5],{},", an array through ",[13,495,45],{},", and each rejects the other at compile time.",[63,498,500],{"id":499},"where-to-next","Where to next",[502,503,504,512,522,529],"ul",{},[505,506,507,511],"li",{},[40,508,509],{"href":42},[13,510,45],{},": the array counterpart, one FieldState per element with reorder-stable keys.",[505,513,514,518,519,521],{},[40,515,517],{"href":516},"\u002Fdocs\u002Fschemas\u002Frecords","Records & maps",": declaring a ",[13,520,356],{}," schema and binding its entries.",[505,523,524,528],{},[40,525,526],{"href":52},[13,527,373],{},": the per-leaf FieldState every entry carries.",[505,530,531,535],{},[40,532,533],{"href":408},[13,534,411],{},": how an entry joins or leaves the record.",[537,538,539],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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":80,"searchDepth":115,"depth":115,"links":541},[542,543,544,545,547,549],{"id":65,"depth":115,"text":66},{"id":364,"depth":115,"text":365},{"id":401,"depth":115,"text":402},{"id":446,"depth":115,"text":546},"form.fields stays the aggregate",{"id":473,"depth":115,"text":548},"list is the array counterpart",{"id":499,"depth":115,"text":500},"form.record reads a record as one FieldState per entry, keyed by the entry's own key, so you iterate dynamic keys without tracking them yourself.","md",{},[554,557,560],{"label":555,"value":556},"Category","Return method",{"label":558,"value":559,"kind":13},"Type","(path) => Readonly\u003CRecord\u003Cstring, FieldState>>",{"label":561,"value":562},"Keyed","Yes, by record key","\u002Fdocs\u002Freading-the-form\u002Frecord",{"title":5,"description":550},null,"docs\u002Freading-the-form\u002Frecord","EhGPcfg-AopzTQyK9xqSPinKLQq8h-aLB7RUVFIa2RQ",1780949758485]