forms.mjs 292 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681
  1. /**
  2. * @license Angular v19.2.4
  3. * (c) 2010-2025 Google LLC. https://angular.io/
  4. * License: MIT
  5. */
  6. import * as i0 from '@angular/core';
  7. import { InjectionToken, Directive, forwardRef, Optional, Inject, ɵisPromise as _isPromise, ɵisSubscribable as _isSubscribable, ɵRuntimeError as _RuntimeError, Self, untracked, computed, signal, EventEmitter, Input, Host, SkipSelf, booleanAttribute, ChangeDetectorRef, Output, inject, Injectable, NgModule, Version } from '@angular/core';
  8. import { ɵgetDOM as _getDOM } from '@angular/common';
  9. import { from, forkJoin, Subject } from 'rxjs';
  10. import { map } from 'rxjs/operators';
  11. /**
  12. * Base class for all ControlValueAccessor classes defined in Forms package.
  13. * Contains common logic and utility functions.
  14. *
  15. * Note: this is an *internal-only* class and should not be extended or used directly in
  16. * applications code.
  17. */
  18. class BaseControlValueAccessor {
  19. _renderer;
  20. _elementRef;
  21. /**
  22. * The registered callback function called when a change or input event occurs on the input
  23. * element.
  24. * @nodoc
  25. */
  26. onChange = (_) => { };
  27. /**
  28. * The registered callback function called when a blur event occurs on the input element.
  29. * @nodoc
  30. */
  31. onTouched = () => { };
  32. constructor(_renderer, _elementRef) {
  33. this._renderer = _renderer;
  34. this._elementRef = _elementRef;
  35. }
  36. /**
  37. * Helper method that sets a property on a target element using the current Renderer
  38. * implementation.
  39. * @nodoc
  40. */
  41. setProperty(key, value) {
  42. this._renderer.setProperty(this._elementRef.nativeElement, key, value);
  43. }
  44. /**
  45. * Registers a function called when the control is touched.
  46. * @nodoc
  47. */
  48. registerOnTouched(fn) {
  49. this.onTouched = fn;
  50. }
  51. /**
  52. * Registers a function called when the control value changes.
  53. * @nodoc
  54. */
  55. registerOnChange(fn) {
  56. this.onChange = fn;
  57. }
  58. /**
  59. * Sets the "disabled" property on the range input element.
  60. * @nodoc
  61. */
  62. setDisabledState(isDisabled) {
  63. this.setProperty('disabled', isDisabled);
  64. }
  65. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseControlValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
  66. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: BaseControlValueAccessor, isStandalone: true, ngImport: i0 });
  67. }
  68. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseControlValueAccessor, decorators: [{
  69. type: Directive
  70. }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }] });
  71. /**
  72. * Base class for all built-in ControlValueAccessor classes (except DefaultValueAccessor, which is
  73. * used in case no other CVAs can be found). We use this class to distinguish between default CVA,
  74. * built-in CVAs and custom CVAs, so that Forms logic can recognize built-in CVAs and treat custom
  75. * ones with higher priority (when both built-in and custom CVAs are present).
  76. *
  77. * Note: this is an *internal-only* class and should not be extended or used directly in
  78. * applications code.
  79. */
  80. class BuiltInControlValueAccessor extends BaseControlValueAccessor {
  81. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BuiltInControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  82. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: BuiltInControlValueAccessor, isStandalone: true, usesInheritance: true, ngImport: i0 });
  83. }
  84. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BuiltInControlValueAccessor, decorators: [{
  85. type: Directive
  86. }] });
  87. /**
  88. * Used to provide a `ControlValueAccessor` for form controls.
  89. *
  90. * See `DefaultValueAccessor` for how to implement one.
  91. *
  92. * @publicApi
  93. */
  94. const NG_VALUE_ACCESSOR = new InjectionToken(ngDevMode ? 'NgValueAccessor' : '');
  95. const CHECKBOX_VALUE_ACCESSOR = {
  96. provide: NG_VALUE_ACCESSOR,
  97. useExisting: forwardRef(() => CheckboxControlValueAccessor),
  98. multi: true,
  99. };
  100. /**
  101. * @description
  102. * A `ControlValueAccessor` for writing a value and listening to changes on a checkbox input
  103. * element.
  104. *
  105. * @usageNotes
  106. *
  107. * ### Using a checkbox with a reactive form.
  108. *
  109. * The following example shows how to use a checkbox with a reactive form.
  110. *
  111. * ```ts
  112. * const rememberLoginControl = new FormControl();
  113. * ```
  114. *
  115. * ```html
  116. * <input type="checkbox" [formControl]="rememberLoginControl">
  117. * ```
  118. *
  119. * @ngModule ReactiveFormsModule
  120. * @ngModule FormsModule
  121. * @publicApi
  122. */
  123. class CheckboxControlValueAccessor extends BuiltInControlValueAccessor {
  124. /**
  125. * Sets the "checked" property on the input element.
  126. * @nodoc
  127. */
  128. writeValue(value) {
  129. this.setProperty('checked', value);
  130. }
  131. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  132. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: CheckboxControlValueAccessor, isStandalone: false, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]", host: { listeners: { "change": "onChange($event.target.checked)", "blur": "onTouched()" } }, providers: [CHECKBOX_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  133. }
  134. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxControlValueAccessor, decorators: [{
  135. type: Directive,
  136. args: [{
  137. selector: 'input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]',
  138. host: { '(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()' },
  139. providers: [CHECKBOX_VALUE_ACCESSOR],
  140. standalone: false,
  141. }]
  142. }] });
  143. const DEFAULT_VALUE_ACCESSOR = {
  144. provide: NG_VALUE_ACCESSOR,
  145. useExisting: forwardRef(() => DefaultValueAccessor),
  146. multi: true,
  147. };
  148. /**
  149. * We must check whether the agent is Android because composition events
  150. * behave differently between iOS and Android.
  151. */
  152. function _isAndroid() {
  153. const userAgent = _getDOM() ? _getDOM().getUserAgent() : '';
  154. return /android (\d+)/.test(userAgent.toLowerCase());
  155. }
  156. /**
  157. * @description
  158. * Provide this token to control if form directives buffer IME input until
  159. * the "compositionend" event occurs.
  160. * @publicApi
  161. */
  162. const COMPOSITION_BUFFER_MODE = new InjectionToken(ngDevMode ? 'CompositionEventMode' : '');
  163. /**
  164. * The default `ControlValueAccessor` for writing a value and listening to changes on input
  165. * elements. The accessor is used by the `FormControlDirective`, `FormControlName`, and
  166. * `NgModel` directives.
  167. *
  168. *
  169. * @usageNotes
  170. *
  171. * ### Using the default value accessor
  172. *
  173. * The following example shows how to use an input element that activates the default value accessor
  174. * (in this case, a text field).
  175. *
  176. * ```ts
  177. * const firstNameControl = new FormControl();
  178. * ```
  179. *
  180. * ```html
  181. * <input type="text" [formControl]="firstNameControl">
  182. * ```
  183. *
  184. * This value accessor is used by default for `<input type="text">` and `<textarea>` elements, but
  185. * you could also use it for custom components that have similar behavior and do not require special
  186. * processing. In order to attach the default value accessor to a custom element, add the
  187. * `ngDefaultControl` attribute as shown below.
  188. *
  189. * ```html
  190. * <custom-input-component ngDefaultControl [(ngModel)]="value"></custom-input-component>
  191. * ```
  192. *
  193. * @ngModule ReactiveFormsModule
  194. * @ngModule FormsModule
  195. * @publicApi
  196. */
  197. class DefaultValueAccessor extends BaseControlValueAccessor {
  198. _compositionMode;
  199. /** Whether the user is creating a composition string (IME events). */
  200. _composing = false;
  201. constructor(renderer, elementRef, _compositionMode) {
  202. super(renderer, elementRef);
  203. this._compositionMode = _compositionMode;
  204. if (this._compositionMode == null) {
  205. this._compositionMode = !_isAndroid();
  206. }
  207. }
  208. /**
  209. * Sets the "value" property on the input element.
  210. * @nodoc
  211. */
  212. writeValue(value) {
  213. const normalizedValue = value == null ? '' : value;
  214. this.setProperty('value', normalizedValue);
  215. }
  216. /** @internal */
  217. _handleInput(value) {
  218. if (!this._compositionMode || (this._compositionMode && !this._composing)) {
  219. this.onChange(value);
  220. }
  221. }
  222. /** @internal */
  223. _compositionStart() {
  224. this._composing = true;
  225. }
  226. /** @internal */
  227. _compositionEnd(value) {
  228. this._composing = false;
  229. this._compositionMode && this.onChange(value);
  230. }
  231. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: COMPOSITION_BUFFER_MODE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  232. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: DefaultValueAccessor, isStandalone: false, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]", host: { listeners: { "input": "$any(this)._handleInput($event.target.value)", "blur": "onTouched()", "compositionstart": "$any(this)._compositionStart()", "compositionend": "$any(this)._compositionEnd($event.target.value)" } }, providers: [DEFAULT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  233. }
  234. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultValueAccessor, decorators: [{
  235. type: Directive,
  236. args: [{
  237. selector: 'input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
  238. // TODO: vsavkin replace the above selector with the one below it once
  239. // https://github.com/angular/angular/issues/3011 is implemented
  240. // selector: '[ngModel],[formControl],[formControlName]',
  241. host: {
  242. '(input)': '$any(this)._handleInput($event.target.value)',
  243. '(blur)': 'onTouched()',
  244. '(compositionstart)': '$any(this)._compositionStart()',
  245. '(compositionend)': '$any(this)._compositionEnd($event.target.value)',
  246. },
  247. providers: [DEFAULT_VALUE_ACCESSOR],
  248. standalone: false,
  249. }]
  250. }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: undefined, decorators: [{
  251. type: Optional
  252. }, {
  253. type: Inject,
  254. args: [COMPOSITION_BUFFER_MODE]
  255. }] }] });
  256. function isEmptyInputValue(value) {
  257. return value == null || lengthOrSize(value) === 0;
  258. }
  259. /**
  260. * Extract the length property in case it's an array or a string.
  261. * Extract the size property in case it's a set.
  262. * Return null else.
  263. * @param value Either an array, set or undefined.
  264. */
  265. function lengthOrSize(value) {
  266. // non-strict comparison is intentional, to check for both `null` and `undefined` values
  267. if (value == null) {
  268. return null;
  269. }
  270. else if (Array.isArray(value) || typeof value === 'string') {
  271. return value.length;
  272. }
  273. else if (value instanceof Set) {
  274. return value.size;
  275. }
  276. return null;
  277. }
  278. /**
  279. * @description
  280. * An `InjectionToken` for registering additional synchronous validators used with
  281. * `AbstractControl`s.
  282. *
  283. * @see {@link NG_ASYNC_VALIDATORS}
  284. *
  285. * @usageNotes
  286. *
  287. * ### Providing a custom validator
  288. *
  289. * The following example registers a custom validator directive. Adding the validator to the
  290. * existing collection of validators requires the `multi: true` option.
  291. *
  292. * ```ts
  293. * @Directive({
  294. * selector: '[customValidator]',
  295. * providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
  296. * })
  297. * class CustomValidatorDirective implements Validator {
  298. * validate(control: AbstractControl): ValidationErrors | null {
  299. * return { 'custom': true };
  300. * }
  301. * }
  302. * ```
  303. *
  304. * @publicApi
  305. */
  306. const NG_VALIDATORS = new InjectionToken(ngDevMode ? 'NgValidators' : '');
  307. /**
  308. * @description
  309. * An `InjectionToken` for registering additional asynchronous validators used with
  310. * `AbstractControl`s.
  311. *
  312. * @see {@link NG_VALIDATORS}
  313. *
  314. * @usageNotes
  315. *
  316. * ### Provide a custom async validator directive
  317. *
  318. * The following example implements the `AsyncValidator` interface to create an
  319. * async validator directive with a custom error key.
  320. *
  321. * ```ts
  322. * @Directive({
  323. * selector: '[customAsyncValidator]',
  324. * providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: CustomAsyncValidatorDirective, multi:
  325. * true}]
  326. * })
  327. * class CustomAsyncValidatorDirective implements AsyncValidator {
  328. * validate(control: AbstractControl): Promise<ValidationErrors|null> {
  329. * return Promise.resolve({'custom': true});
  330. * }
  331. * }
  332. * ```
  333. *
  334. * @publicApi
  335. */
  336. const NG_ASYNC_VALIDATORS = new InjectionToken(ngDevMode ? 'NgAsyncValidators' : '');
  337. /**
  338. * A regular expression that matches valid e-mail addresses.
  339. *
  340. * At a high level, this regexp matches e-mail addresses of the format `local-part@tld`, where:
  341. * - `local-part` consists of one or more of the allowed characters (alphanumeric and some
  342. * punctuation symbols).
  343. * - `local-part` cannot begin or end with a period (`.`).
  344. * - `local-part` cannot be longer than 64 characters.
  345. * - `tld` consists of one or more `labels` separated by periods (`.`). For example `localhost` or
  346. * `foo.com`.
  347. * - A `label` consists of one or more of the allowed characters (alphanumeric, dashes (`-`) and
  348. * periods (`.`)).
  349. * - A `label` cannot begin or end with a dash (`-`) or a period (`.`).
  350. * - A `label` cannot be longer than 63 characters.
  351. * - The whole address cannot be longer than 254 characters.
  352. *
  353. * ## Implementation background
  354. *
  355. * This regexp was ported over from AngularJS (see there for git history):
  356. * https://github.com/angular/angular.js/blob/c133ef836/src/ng/directive/input.js#L27
  357. * It is based on the
  358. * [WHATWG version](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
  359. * some enhancements to incorporate more RFC rules (such as rules related to domain names and the
  360. * lengths of different parts of the address). The main differences from the WHATWG version are:
  361. * - Disallow `local-part` to begin or end with a period (`.`).
  362. * - Disallow `local-part` length to exceed 64 characters.
  363. * - Disallow total address length to exceed 254 characters.
  364. *
  365. * See [this commit](https://github.com/angular/angular.js/commit/f3f5cf72e) for more details.
  366. */
  367. const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
  368. /**
  369. * @description
  370. * Provides a set of built-in validators that can be used by form controls.
  371. *
  372. * A validator is a function that processes a `FormControl` or collection of
  373. * controls and returns an error map or null. A null map means that validation has passed.
  374. *
  375. * @see [Form Validation](guide/forms/form-validation)
  376. *
  377. * @publicApi
  378. */
  379. class Validators {
  380. /**
  381. * @description
  382. * Validator that requires the control's value to be greater than or equal to the provided number.
  383. *
  384. * @usageNotes
  385. *
  386. * ### Validate against a minimum of 3
  387. *
  388. * ```ts
  389. * const control = new FormControl(2, Validators.min(3));
  390. *
  391. * console.log(control.errors); // {min: {min: 3, actual: 2}}
  392. * ```
  393. *
  394. * @returns A validator function that returns an error map with the
  395. * `min` property if the validation check fails, otherwise `null`.
  396. *
  397. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  398. *
  399. */
  400. static min(min) {
  401. return minValidator(min);
  402. }
  403. /**
  404. * @description
  405. * Validator that requires the control's value to be less than or equal to the provided number.
  406. *
  407. * @usageNotes
  408. *
  409. * ### Validate against a maximum of 15
  410. *
  411. * ```ts
  412. * const control = new FormControl(16, Validators.max(15));
  413. *
  414. * console.log(control.errors); // {max: {max: 15, actual: 16}}
  415. * ```
  416. *
  417. * @returns A validator function that returns an error map with the
  418. * `max` property if the validation check fails, otherwise `null`.
  419. *
  420. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  421. *
  422. */
  423. static max(max) {
  424. return maxValidator(max);
  425. }
  426. /**
  427. * @description
  428. * Validator that requires the control have a non-empty value.
  429. *
  430. * @usageNotes
  431. *
  432. * ### Validate that the field is non-empty
  433. *
  434. * ```ts
  435. * const control = new FormControl('', Validators.required);
  436. *
  437. * console.log(control.errors); // {required: true}
  438. * ```
  439. *
  440. * @returns An error map with the `required` property
  441. * if the validation check fails, otherwise `null`.
  442. *
  443. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  444. *
  445. */
  446. static required(control) {
  447. return requiredValidator(control);
  448. }
  449. /**
  450. * @description
  451. * Validator that requires the control's value be true. This validator is commonly
  452. * used for required checkboxes.
  453. *
  454. * @usageNotes
  455. *
  456. * ### Validate that the field value is true
  457. *
  458. * ```ts
  459. * const control = new FormControl('some value', Validators.requiredTrue);
  460. *
  461. * console.log(control.errors); // {required: true}
  462. * ```
  463. *
  464. * @returns An error map that contains the `required` property
  465. * set to `true` if the validation check fails, otherwise `null`.
  466. *
  467. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  468. *
  469. */
  470. static requiredTrue(control) {
  471. return requiredTrueValidator(control);
  472. }
  473. /**
  474. * @description
  475. * Validator that requires the control's value pass an email validation test.
  476. *
  477. * Tests the value using a [regular
  478. * expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
  479. * pattern suitable for common use cases. The pattern is based on the definition of a valid email
  480. * address in the [WHATWG HTML
  481. * specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
  482. * some enhancements to incorporate more RFC rules (such as rules related to domain names and the
  483. * lengths of different parts of the address).
  484. *
  485. * The differences from the WHATWG version include:
  486. * - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`).
  487. * - Disallow `local-part` to be longer than 64 characters.
  488. * - Disallow the whole address to be longer than 254 characters.
  489. *
  490. * If this pattern does not satisfy your business needs, you can use `Validators.pattern()` to
  491. * validate the value against a different pattern.
  492. *
  493. * @usageNotes
  494. *
  495. * ### Validate that the field matches a valid email pattern
  496. *
  497. * ```ts
  498. * const control = new FormControl('bad@', Validators.email);
  499. *
  500. * console.log(control.errors); // {email: true}
  501. * ```
  502. *
  503. * @returns An error map with the `email` property
  504. * if the validation check fails, otherwise `null`.
  505. *
  506. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  507. *
  508. */
  509. static email(control) {
  510. return emailValidator(control);
  511. }
  512. /**
  513. * @description
  514. * Validator that requires the number of items in the control's value to be greater than or equal
  515. * to the provided minimum length. This validator is also provided by default if you use
  516. * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used
  517. * only for types that have a numeric `length` or `size` property, such as strings, arrays or
  518. * sets. The `minLength` validator logic is also not invoked for values when their `length` or
  519. * `size` property is 0 (for example in case of an empty string or an empty array), to support
  520. * optional controls. You can use the standard `required` validator if empty values should not be
  521. * considered valid.
  522. *
  523. * @usageNotes
  524. *
  525. * ### Validate that the field has a minimum of 3 characters
  526. *
  527. * ```ts
  528. * const control = new FormControl('ng', Validators.minLength(3));
  529. *
  530. * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}
  531. * ```
  532. *
  533. * ```html
  534. * <input minlength="5">
  535. * ```
  536. *
  537. * @returns A validator function that returns an error map with the
  538. * `minlength` property if the validation check fails, otherwise `null`.
  539. *
  540. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  541. *
  542. */
  543. static minLength(minLength) {
  544. return minLengthValidator(minLength);
  545. }
  546. /**
  547. * @description
  548. * Validator that requires the number of items in the control's value to be less than or equal
  549. * to the provided maximum length. This validator is also provided by default if you use
  550. * the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used
  551. * only for types that have a numeric `length` or `size` property, such as strings, arrays or
  552. * sets.
  553. *
  554. * @usageNotes
  555. *
  556. * ### Validate that the field has maximum of 5 characters
  557. *
  558. * ```ts
  559. * const control = new FormControl('Angular', Validators.maxLength(5));
  560. *
  561. * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}
  562. * ```
  563. *
  564. * ```html
  565. * <input maxlength="5">
  566. * ```
  567. *
  568. * @returns A validator function that returns an error map with the
  569. * `maxlength` property if the validation check fails, otherwise `null`.
  570. *
  571. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  572. *
  573. */
  574. static maxLength(maxLength) {
  575. return maxLengthValidator(maxLength);
  576. }
  577. /**
  578. * @description
  579. * Validator that requires the control's value to match a regex pattern. This validator is also
  580. * provided by default if you use the HTML5 `pattern` attribute.
  581. *
  582. * @usageNotes
  583. *
  584. * ### Validate that the field only contains letters or spaces
  585. *
  586. * ```ts
  587. * const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));
  588. *
  589. * console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}
  590. * ```
  591. *
  592. * ```html
  593. * <input pattern="[a-zA-Z ]*">
  594. * ```
  595. *
  596. * ### Pattern matching with the global or sticky flag
  597. *
  598. * `RegExp` objects created with the `g` or `y` flags that are passed into `Validators.pattern`
  599. * can produce different results on the same input when validations are run consecutively. This is
  600. * due to how the behavior of `RegExp.prototype.test` is
  601. * specified in [ECMA-262](https://tc39.es/ecma262/#sec-regexpbuiltinexec)
  602. * (`RegExp` preserves the index of the last match when the global or sticky flag is used).
  603. * Due to this behavior, it is recommended that when using
  604. * `Validators.pattern` you **do not** pass in a `RegExp` object with either the global or sticky
  605. * flag enabled.
  606. *
  607. * ```ts
  608. * // Not recommended (since the `g` flag is used)
  609. * const controlOne = new FormControl('1', Validators.pattern(/foo/g));
  610. *
  611. * // Good
  612. * const controlTwo = new FormControl('1', Validators.pattern(/foo/));
  613. * ```
  614. *
  615. * @param pattern A regular expression to be used as is to test the values, or a string.
  616. * If a string is passed, the `^` character is prepended and the `$` character is
  617. * appended to the provided string (if not already present), and the resulting regular
  618. * expression is used to test the values.
  619. *
  620. * @returns A validator function that returns an error map with the
  621. * `pattern` property if the validation check fails, otherwise `null`.
  622. *
  623. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  624. *
  625. */
  626. static pattern(pattern) {
  627. return patternValidator(pattern);
  628. }
  629. /**
  630. * @description
  631. * Validator that performs no operation.
  632. *
  633. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  634. *
  635. */
  636. static nullValidator(control) {
  637. return nullValidator();
  638. }
  639. static compose(validators) {
  640. return compose(validators);
  641. }
  642. /**
  643. * @description
  644. * Compose multiple async validators into a single function that returns the union
  645. * of the individual error objects for the provided control.
  646. *
  647. * @returns A validator function that returns an error map with the
  648. * merged error objects of the async validators if the validation check fails, otherwise `null`.
  649. *
  650. * @see {@link /api/forms/AbstractControl#updateValueAndValidity updateValueAndValidity}
  651. *
  652. */
  653. static composeAsync(validators) {
  654. return composeAsync(validators);
  655. }
  656. }
  657. /**
  658. * Validator that requires the control's value to be greater than or equal to the provided number.
  659. * See `Validators.min` for additional information.
  660. */
  661. function minValidator(min) {
  662. return (control) => {
  663. if (control.value == null || min == null) {
  664. return null; // don't validate empty values to allow optional controls
  665. }
  666. const value = parseFloat(control.value);
  667. // Controls with NaN values after parsing should be treated as not having a
  668. // minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
  669. return !isNaN(value) && value < min ? { 'min': { 'min': min, 'actual': control.value } } : null;
  670. };
  671. }
  672. /**
  673. * Validator that requires the control's value to be less than or equal to the provided number.
  674. * See `Validators.max` for additional information.
  675. */
  676. function maxValidator(max) {
  677. return (control) => {
  678. if (control.value == null || max == null) {
  679. return null; // don't validate empty values to allow optional controls
  680. }
  681. const value = parseFloat(control.value);
  682. // Controls with NaN values after parsing should be treated as not having a
  683. // maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
  684. return !isNaN(value) && value > max ? { 'max': { 'max': max, 'actual': control.value } } : null;
  685. };
  686. }
  687. /**
  688. * Validator that requires the control have a non-empty value.
  689. * See `Validators.required` for additional information.
  690. */
  691. function requiredValidator(control) {
  692. return isEmptyInputValue(control.value) ? { 'required': true } : null;
  693. }
  694. /**
  695. * Validator that requires the control's value be true. This validator is commonly
  696. * used for required checkboxes.
  697. * See `Validators.requiredTrue` for additional information.
  698. */
  699. function requiredTrueValidator(control) {
  700. return control.value === true ? null : { 'required': true };
  701. }
  702. /**
  703. * Validator that requires the control's value pass an email validation test.
  704. * See `Validators.email` for additional information.
  705. */
  706. function emailValidator(control) {
  707. if (isEmptyInputValue(control.value)) {
  708. return null; // don't validate empty values to allow optional controls
  709. }
  710. return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
  711. }
  712. /**
  713. * Validator that requires the number of items in the control's value to be greater than or equal
  714. * to the provided minimum length. See `Validators.minLength` for additional information.
  715. *
  716. * The minLengthValidator respects every length property in an object, regardless of whether it's an array.
  717. * For example, the object {id: 1, length: 0, width: 0} should be validated.
  718. */
  719. function minLengthValidator(minLength) {
  720. return (control) => {
  721. const length = control.value?.length ?? lengthOrSize(control.value);
  722. if (length === null || length === 0) {
  723. // don't validate empty values to allow optional controls
  724. // don't validate values without `length` or `size` property
  725. return null;
  726. }
  727. return length < minLength
  728. ? { 'minlength': { 'requiredLength': minLength, 'actualLength': length } }
  729. : null;
  730. };
  731. }
  732. /**
  733. * Validator that requires the number of items in the control's value to be less than or equal
  734. * to the provided maximum length. See `Validators.maxLength` for additional information.
  735. *
  736. * The maxLengthValidator respects every length property in an object, regardless of whether it's an array.
  737. * For example, the object {id: 1, length: 0, width: 0} should be validated.
  738. */
  739. function maxLengthValidator(maxLength) {
  740. return (control) => {
  741. const length = control.value?.length ?? lengthOrSize(control.value);
  742. if (length !== null && length > maxLength) {
  743. return { 'maxlength': { 'requiredLength': maxLength, 'actualLength': length } };
  744. }
  745. return null;
  746. };
  747. }
  748. /**
  749. * Validator that requires the control's value to match a regex pattern.
  750. * See `Validators.pattern` for additional information.
  751. */
  752. function patternValidator(pattern) {
  753. if (!pattern)
  754. return nullValidator;
  755. let regex;
  756. let regexStr;
  757. if (typeof pattern === 'string') {
  758. regexStr = '';
  759. if (pattern.charAt(0) !== '^')
  760. regexStr += '^';
  761. regexStr += pattern;
  762. if (pattern.charAt(pattern.length - 1) !== '$')
  763. regexStr += '$';
  764. regex = new RegExp(regexStr);
  765. }
  766. else {
  767. regexStr = pattern.toString();
  768. regex = pattern;
  769. }
  770. return (control) => {
  771. if (isEmptyInputValue(control.value)) {
  772. return null; // don't validate empty values to allow optional controls
  773. }
  774. const value = control.value;
  775. return regex.test(value)
  776. ? null
  777. : { 'pattern': { 'requiredPattern': regexStr, 'actualValue': value } };
  778. };
  779. }
  780. /**
  781. * Function that has `ValidatorFn` shape, but performs no operation.
  782. */
  783. function nullValidator(control) {
  784. return null;
  785. }
  786. function isPresent(o) {
  787. return o != null;
  788. }
  789. function toObservable(value) {
  790. const obs = _isPromise(value) ? from(value) : value;
  791. if ((typeof ngDevMode === 'undefined' || ngDevMode) && !_isSubscribable(obs)) {
  792. let errorMessage = `Expected async validator to return Promise or Observable.`;
  793. // A synchronous validator will return object or null.
  794. if (typeof value === 'object') {
  795. errorMessage +=
  796. ' Are you using a synchronous validator where an async validator is expected?';
  797. }
  798. throw new _RuntimeError(-1101 /* RuntimeErrorCode.WRONG_VALIDATOR_RETURN_TYPE */, errorMessage);
  799. }
  800. return obs;
  801. }
  802. function mergeErrors(arrayOfErrors) {
  803. let res = {};
  804. arrayOfErrors.forEach((errors) => {
  805. res = errors != null ? { ...res, ...errors } : res;
  806. });
  807. return Object.keys(res).length === 0 ? null : res;
  808. }
  809. function executeValidators(control, validators) {
  810. return validators.map((validator) => validator(control));
  811. }
  812. function isValidatorFn(validator) {
  813. return !validator.validate;
  814. }
  815. /**
  816. * Given the list of validators that may contain both functions as well as classes, return the list
  817. * of validator functions (convert validator classes into validator functions). This is needed to
  818. * have consistent structure in validators list before composing them.
  819. *
  820. * @param validators The set of validators that may contain validators both in plain function form
  821. * as well as represented as a validator class.
  822. */
  823. function normalizeValidators(validators) {
  824. return validators.map((validator) => {
  825. return isValidatorFn(validator)
  826. ? validator
  827. : ((c) => validator.validate(c));
  828. });
  829. }
  830. /**
  831. * Merges synchronous validators into a single validator function.
  832. * See `Validators.compose` for additional information.
  833. */
  834. function compose(validators) {
  835. if (!validators)
  836. return null;
  837. const presentValidators = validators.filter(isPresent);
  838. if (presentValidators.length == 0)
  839. return null;
  840. return function (control) {
  841. return mergeErrors(executeValidators(control, presentValidators));
  842. };
  843. }
  844. /**
  845. * Accepts a list of validators of different possible shapes (`Validator` and `ValidatorFn`),
  846. * normalizes the list (converts everything to `ValidatorFn`) and merges them into a single
  847. * validator function.
  848. */
  849. function composeValidators(validators) {
  850. return validators != null ? compose(normalizeValidators(validators)) : null;
  851. }
  852. /**
  853. * Merges asynchronous validators into a single validator function.
  854. * See `Validators.composeAsync` for additional information.
  855. */
  856. function composeAsync(validators) {
  857. if (!validators)
  858. return null;
  859. const presentValidators = validators.filter(isPresent);
  860. if (presentValidators.length == 0)
  861. return null;
  862. return function (control) {
  863. const observables = executeValidators(control, presentValidators).map(toObservable);
  864. return forkJoin(observables).pipe(map(mergeErrors));
  865. };
  866. }
  867. /**
  868. * Accepts a list of async validators of different possible shapes (`AsyncValidator` and
  869. * `AsyncValidatorFn`), normalizes the list (converts everything to `AsyncValidatorFn`) and merges
  870. * them into a single validator function.
  871. */
  872. function composeAsyncValidators(validators) {
  873. return validators != null
  874. ? composeAsync(normalizeValidators(validators))
  875. : null;
  876. }
  877. /**
  878. * Merges raw control validators with a given directive validator and returns the combined list of
  879. * validators as an array.
  880. */
  881. function mergeValidators(controlValidators, dirValidator) {
  882. if (controlValidators === null)
  883. return [dirValidator];
  884. return Array.isArray(controlValidators)
  885. ? [...controlValidators, dirValidator]
  886. : [controlValidators, dirValidator];
  887. }
  888. /**
  889. * Retrieves the list of raw synchronous validators attached to a given control.
  890. */
  891. function getControlValidators(control) {
  892. return control._rawValidators;
  893. }
  894. /**
  895. * Retrieves the list of raw asynchronous validators attached to a given control.
  896. */
  897. function getControlAsyncValidators(control) {
  898. return control._rawAsyncValidators;
  899. }
  900. /**
  901. * Accepts a singleton validator, an array, or null, and returns an array type with the provided
  902. * validators.
  903. *
  904. * @param validators A validator, validators, or null.
  905. * @returns A validators array.
  906. */
  907. function makeValidatorsArray(validators) {
  908. if (!validators)
  909. return [];
  910. return Array.isArray(validators) ? validators : [validators];
  911. }
  912. /**
  913. * Determines whether a validator or validators array has a given validator.
  914. *
  915. * @param validators The validator or validators to compare against.
  916. * @param validator The validator to check.
  917. * @returns Whether the validator is present.
  918. */
  919. function hasValidator(validators, validator) {
  920. return Array.isArray(validators) ? validators.includes(validator) : validators === validator;
  921. }
  922. /**
  923. * Combines two arrays of validators into one. If duplicates are provided, only one will be added.
  924. *
  925. * @param validators The new validators.
  926. * @param currentValidators The base array of current validators.
  927. * @returns An array of validators.
  928. */
  929. function addValidators(validators, currentValidators) {
  930. const current = makeValidatorsArray(currentValidators);
  931. const validatorsToAdd = makeValidatorsArray(validators);
  932. validatorsToAdd.forEach((v) => {
  933. // Note: if there are duplicate entries in the new validators array,
  934. // only the first one would be added to the current list of validators.
  935. // Duplicate ones would be ignored since `hasValidator` would detect
  936. // the presence of a validator function and we update the current list in place.
  937. if (!hasValidator(current, v)) {
  938. current.push(v);
  939. }
  940. });
  941. return current;
  942. }
  943. function removeValidators(validators, currentValidators) {
  944. return makeValidatorsArray(currentValidators).filter((v) => !hasValidator(validators, v));
  945. }
  946. /**
  947. * @description
  948. * Base class for control directives.
  949. *
  950. * This class is only used internally in the `ReactiveFormsModule` and the `FormsModule`.
  951. *
  952. * @publicApi
  953. */
  954. class AbstractControlDirective {
  955. /**
  956. * @description
  957. * Reports the value of the control if it is present, otherwise null.
  958. */
  959. get value() {
  960. return this.control ? this.control.value : null;
  961. }
  962. /**
  963. * @description
  964. * Reports whether the control is valid. A control is considered valid if no
  965. * validation errors exist with the current value.
  966. * If the control is not present, null is returned.
  967. */
  968. get valid() {
  969. return this.control ? this.control.valid : null;
  970. }
  971. /**
  972. * @description
  973. * Reports whether the control is invalid, meaning that an error exists in the input value.
  974. * If the control is not present, null is returned.
  975. */
  976. get invalid() {
  977. return this.control ? this.control.invalid : null;
  978. }
  979. /**
  980. * @description
  981. * Reports whether a control is pending, meaning that async validation is occurring and
  982. * errors are not yet available for the input value. If the control is not present, null is
  983. * returned.
  984. */
  985. get pending() {
  986. return this.control ? this.control.pending : null;
  987. }
  988. /**
  989. * @description
  990. * Reports whether the control is disabled, meaning that the control is disabled
  991. * in the UI and is exempt from validation checks and excluded from aggregate
  992. * values of ancestor controls. If the control is not present, null is returned.
  993. */
  994. get disabled() {
  995. return this.control ? this.control.disabled : null;
  996. }
  997. /**
  998. * @description
  999. * Reports whether the control is enabled, meaning that the control is included in ancestor
  1000. * calculations of validity or value. If the control is not present, null is returned.
  1001. */
  1002. get enabled() {
  1003. return this.control ? this.control.enabled : null;
  1004. }
  1005. /**
  1006. * @description
  1007. * Reports the control's validation errors. If the control is not present, null is returned.
  1008. */
  1009. get errors() {
  1010. return this.control ? this.control.errors : null;
  1011. }
  1012. /**
  1013. * @description
  1014. * Reports whether the control is pristine, meaning that the user has not yet changed
  1015. * the value in the UI. If the control is not present, null is returned.
  1016. */
  1017. get pristine() {
  1018. return this.control ? this.control.pristine : null;
  1019. }
  1020. /**
  1021. * @description
  1022. * Reports whether the control is dirty, meaning that the user has changed
  1023. * the value in the UI. If the control is not present, null is returned.
  1024. */
  1025. get dirty() {
  1026. return this.control ? this.control.dirty : null;
  1027. }
  1028. /**
  1029. * @description
  1030. * Reports whether the control is touched, meaning that the user has triggered
  1031. * a `blur` event on it. If the control is not present, null is returned.
  1032. */
  1033. get touched() {
  1034. return this.control ? this.control.touched : null;
  1035. }
  1036. /**
  1037. * @description
  1038. * Reports the validation status of the control. Possible values include:
  1039. * 'VALID', 'INVALID', 'DISABLED', and 'PENDING'.
  1040. * If the control is not present, null is returned.
  1041. */
  1042. get status() {
  1043. return this.control ? this.control.status : null;
  1044. }
  1045. /**
  1046. * @description
  1047. * Reports whether the control is untouched, meaning that the user has not yet triggered
  1048. * a `blur` event on it. If the control is not present, null is returned.
  1049. */
  1050. get untouched() {
  1051. return this.control ? this.control.untouched : null;
  1052. }
  1053. /**
  1054. * @description
  1055. * Returns a multicasting observable that emits a validation status whenever it is
  1056. * calculated for the control. If the control is not present, null is returned.
  1057. */
  1058. get statusChanges() {
  1059. return this.control ? this.control.statusChanges : null;
  1060. }
  1061. /**
  1062. * @description
  1063. * Returns a multicasting observable of value changes for the control that emits every time the
  1064. * value of the control changes in the UI or programmatically.
  1065. * If the control is not present, null is returned.
  1066. */
  1067. get valueChanges() {
  1068. return this.control ? this.control.valueChanges : null;
  1069. }
  1070. /**
  1071. * @description
  1072. * Returns an array that represents the path from the top-level form to this control.
  1073. * Each index is the string name of the control on that level.
  1074. */
  1075. get path() {
  1076. return null;
  1077. }
  1078. /**
  1079. * Contains the result of merging synchronous validators into a single validator function
  1080. * (combined using `Validators.compose`).
  1081. */
  1082. _composedValidatorFn;
  1083. /**
  1084. * Contains the result of merging asynchronous validators into a single validator function
  1085. * (combined using `Validators.composeAsync`).
  1086. */
  1087. _composedAsyncValidatorFn;
  1088. /**
  1089. * Set of synchronous validators as they were provided while calling `setValidators` function.
  1090. * @internal
  1091. */
  1092. _rawValidators = [];
  1093. /**
  1094. * Set of asynchronous validators as they were provided while calling `setAsyncValidators`
  1095. * function.
  1096. * @internal
  1097. */
  1098. _rawAsyncValidators = [];
  1099. /**
  1100. * Sets synchronous validators for this directive.
  1101. * @internal
  1102. */
  1103. _setValidators(validators) {
  1104. this._rawValidators = validators || [];
  1105. this._composedValidatorFn = composeValidators(this._rawValidators);
  1106. }
  1107. /**
  1108. * Sets asynchronous validators for this directive.
  1109. * @internal
  1110. */
  1111. _setAsyncValidators(validators) {
  1112. this._rawAsyncValidators = validators || [];
  1113. this._composedAsyncValidatorFn = composeAsyncValidators(this._rawAsyncValidators);
  1114. }
  1115. /**
  1116. * @description
  1117. * Synchronous validator function composed of all the synchronous validators registered with this
  1118. * directive.
  1119. */
  1120. get validator() {
  1121. return this._composedValidatorFn || null;
  1122. }
  1123. /**
  1124. * @description
  1125. * Asynchronous validator function composed of all the asynchronous validators registered with
  1126. * this directive.
  1127. */
  1128. get asyncValidator() {
  1129. return this._composedAsyncValidatorFn || null;
  1130. }
  1131. /*
  1132. * The set of callbacks to be invoked when directive instance is being destroyed.
  1133. */
  1134. _onDestroyCallbacks = [];
  1135. /**
  1136. * Internal function to register callbacks that should be invoked
  1137. * when directive instance is being destroyed.
  1138. * @internal
  1139. */
  1140. _registerOnDestroy(fn) {
  1141. this._onDestroyCallbacks.push(fn);
  1142. }
  1143. /**
  1144. * Internal function to invoke all registered "on destroy" callbacks.
  1145. * Note: calling this function also clears the list of callbacks.
  1146. * @internal
  1147. */
  1148. _invokeOnDestroyCallbacks() {
  1149. this._onDestroyCallbacks.forEach((fn) => fn());
  1150. this._onDestroyCallbacks = [];
  1151. }
  1152. /**
  1153. * @description
  1154. * Resets the control with the provided value if the control is present.
  1155. */
  1156. reset(value = undefined) {
  1157. if (this.control)
  1158. this.control.reset(value);
  1159. }
  1160. /**
  1161. * @description
  1162. * Reports whether the control with the given path has the error specified.
  1163. *
  1164. * @param errorCode The code of the error to check
  1165. * @param path A list of control names that designates how to move from the current control
  1166. * to the control that should be queried for errors.
  1167. *
  1168. * @usageNotes
  1169. * For example, for the following `FormGroup`:
  1170. *
  1171. * ```ts
  1172. * form = new FormGroup({
  1173. * address: new FormGroup({ street: new FormControl() })
  1174. * });
  1175. * ```
  1176. *
  1177. * The path to the 'street' control from the root form would be 'address' -> 'street'.
  1178. *
  1179. * It can be provided to this method in one of two formats:
  1180. *
  1181. * 1. An array of string control names, e.g. `['address', 'street']`
  1182. * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
  1183. *
  1184. * If no path is given, this method checks for the error on the current control.
  1185. *
  1186. * @returns whether the given error is present in the control at the given path.
  1187. *
  1188. * If the control is not present, false is returned.
  1189. */
  1190. hasError(errorCode, path) {
  1191. return this.control ? this.control.hasError(errorCode, path) : false;
  1192. }
  1193. /**
  1194. * @description
  1195. * Reports error data for the control with the given path.
  1196. *
  1197. * @param errorCode The code of the error to check
  1198. * @param path A list of control names that designates how to move from the current control
  1199. * to the control that should be queried for errors.
  1200. *
  1201. * @usageNotes
  1202. * For example, for the following `FormGroup`:
  1203. *
  1204. * ```ts
  1205. * form = new FormGroup({
  1206. * address: new FormGroup({ street: new FormControl() })
  1207. * });
  1208. * ```
  1209. *
  1210. * The path to the 'street' control from the root form would be 'address' -> 'street'.
  1211. *
  1212. * It can be provided to this method in one of two formats:
  1213. *
  1214. * 1. An array of string control names, e.g. `['address', 'street']`
  1215. * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
  1216. *
  1217. * @returns error data for that particular error. If the control or error is not present,
  1218. * null is returned.
  1219. */
  1220. getError(errorCode, path) {
  1221. return this.control ? this.control.getError(errorCode, path) : null;
  1222. }
  1223. }
  1224. /**
  1225. * @description
  1226. * A base class for directives that contain multiple registered instances of `NgControl`.
  1227. * Only used by the forms module.
  1228. *
  1229. * @publicApi
  1230. */
  1231. class ControlContainer extends AbstractControlDirective {
  1232. /**
  1233. * @description
  1234. * The name for the control
  1235. */
  1236. // TODO(issue/24571): remove '!'.
  1237. name;
  1238. /**
  1239. * @description
  1240. * The top-level form directive for the control.
  1241. */
  1242. get formDirective() {
  1243. return null;
  1244. }
  1245. /**
  1246. * @description
  1247. * The path to this group.
  1248. */
  1249. get path() {
  1250. return null;
  1251. }
  1252. }
  1253. /**
  1254. * @description
  1255. * A base class that all `FormControl`-based directives extend. It binds a `FormControl`
  1256. * object to a DOM element.
  1257. *
  1258. * @publicApi
  1259. */
  1260. class NgControl extends AbstractControlDirective {
  1261. /**
  1262. * @description
  1263. * The parent form for the control.
  1264. *
  1265. * @internal
  1266. */
  1267. _parent = null;
  1268. /**
  1269. * @description
  1270. * The name for the control
  1271. */
  1272. name = null;
  1273. /**
  1274. * @description
  1275. * The value accessor for the control
  1276. */
  1277. valueAccessor = null;
  1278. }
  1279. // DO NOT REFACTOR!
  1280. // Each status is represented by a separate function to make sure that
  1281. // advanced Closure Compiler optimizations related to property renaming
  1282. // can work correctly.
  1283. class AbstractControlStatus {
  1284. _cd;
  1285. constructor(cd) {
  1286. this._cd = cd;
  1287. }
  1288. get isTouched() {
  1289. // track the touched signal
  1290. this._cd?.control?._touched?.();
  1291. return !!this._cd?.control?.touched;
  1292. }
  1293. get isUntouched() {
  1294. return !!this._cd?.control?.untouched;
  1295. }
  1296. get isPristine() {
  1297. // track the pristine signal
  1298. this._cd?.control?._pristine?.();
  1299. return !!this._cd?.control?.pristine;
  1300. }
  1301. get isDirty() {
  1302. // pristine signal already tracked above
  1303. return !!this._cd?.control?.dirty;
  1304. }
  1305. get isValid() {
  1306. // track the status signal
  1307. this._cd?.control?._status?.();
  1308. return !!this._cd?.control?.valid;
  1309. }
  1310. get isInvalid() {
  1311. // status signal already tracked above
  1312. return !!this._cd?.control?.invalid;
  1313. }
  1314. get isPending() {
  1315. // status signal already tracked above
  1316. return !!this._cd?.control?.pending;
  1317. }
  1318. get isSubmitted() {
  1319. // track the submitted signal
  1320. this._cd?._submitted?.();
  1321. // We check for the `submitted` field from `NgForm` and `FormGroupDirective` classes, but
  1322. // we avoid instanceof checks to prevent non-tree-shakable references to those types.
  1323. return !!this._cd?.submitted;
  1324. }
  1325. }
  1326. const ngControlStatusHost = {
  1327. '[class.ng-untouched]': 'isUntouched',
  1328. '[class.ng-touched]': 'isTouched',
  1329. '[class.ng-pristine]': 'isPristine',
  1330. '[class.ng-dirty]': 'isDirty',
  1331. '[class.ng-valid]': 'isValid',
  1332. '[class.ng-invalid]': 'isInvalid',
  1333. '[class.ng-pending]': 'isPending',
  1334. };
  1335. const ngGroupStatusHost = {
  1336. ...ngControlStatusHost,
  1337. '[class.ng-submitted]': 'isSubmitted',
  1338. };
  1339. /**
  1340. * @description
  1341. * Directive automatically applied to Angular form controls that sets CSS classes
  1342. * based on control status.
  1343. *
  1344. * @usageNotes
  1345. *
  1346. * ### CSS classes applied
  1347. *
  1348. * The following classes are applied as the properties become true:
  1349. *
  1350. * * ng-valid
  1351. * * ng-invalid
  1352. * * ng-pending
  1353. * * ng-pristine
  1354. * * ng-dirty
  1355. * * ng-untouched
  1356. * * ng-touched
  1357. *
  1358. * @ngModule ReactiveFormsModule
  1359. * @ngModule FormsModule
  1360. * @publicApi
  1361. */
  1362. class NgControlStatus extends AbstractControlStatus {
  1363. constructor(cd) {
  1364. super(cd);
  1365. }
  1366. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgControlStatus, deps: [{ token: NgControl, self: true }], target: i0.ɵɵFactoryTarget.Directive });
  1367. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgControlStatus, isStandalone: false, selector: "[formControlName],[ngModel],[formControl]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending" } }, usesInheritance: true, ngImport: i0 });
  1368. }
  1369. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgControlStatus, decorators: [{
  1370. type: Directive,
  1371. args: [{
  1372. selector: '[formControlName],[ngModel],[formControl]',
  1373. host: ngControlStatusHost,
  1374. standalone: false,
  1375. }]
  1376. }], ctorParameters: () => [{ type: NgControl, decorators: [{
  1377. type: Self
  1378. }] }] });
  1379. /**
  1380. * @description
  1381. * Directive automatically applied to Angular form groups that sets CSS classes
  1382. * based on control status (valid/invalid/dirty/etc). On groups, this includes the additional
  1383. * class ng-submitted.
  1384. *
  1385. * @see {@link NgControlStatus}
  1386. *
  1387. * @ngModule ReactiveFormsModule
  1388. * @ngModule FormsModule
  1389. * @publicApi
  1390. */
  1391. class NgControlStatusGroup extends AbstractControlStatus {
  1392. constructor(cd) {
  1393. super(cd);
  1394. }
  1395. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgControlStatusGroup, deps: [{ token: ControlContainer, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
  1396. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgControlStatusGroup, isStandalone: false, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending", "class.ng-submitted": "isSubmitted" } }, usesInheritance: true, ngImport: i0 });
  1397. }
  1398. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgControlStatusGroup, decorators: [{
  1399. type: Directive,
  1400. args: [{
  1401. selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
  1402. host: ngGroupStatusHost,
  1403. standalone: false,
  1404. }]
  1405. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  1406. type: Optional
  1407. }, {
  1408. type: Self
  1409. }] }] });
  1410. const formControlNameExample = `
  1411. <div [formGroup]="myGroup">
  1412. <input formControlName="firstName">
  1413. </div>
  1414. In your class:
  1415. this.myGroup = new FormGroup({
  1416. firstName: new FormControl()
  1417. });`;
  1418. const formGroupNameExample = `
  1419. <div [formGroup]="myGroup">
  1420. <div formGroupName="person">
  1421. <input formControlName="firstName">
  1422. </div>
  1423. </div>
  1424. In your class:
  1425. this.myGroup = new FormGroup({
  1426. person: new FormGroup({ firstName: new FormControl() })
  1427. });`;
  1428. const formArrayNameExample = `
  1429. <div [formGroup]="myGroup">
  1430. <div formArrayName="cities">
  1431. <div *ngFor="let city of cityArray.controls; index as i">
  1432. <input [formControlName]="i">
  1433. </div>
  1434. </div>
  1435. </div>
  1436. In your class:
  1437. this.cityArray = new FormArray([new FormControl('SF')]);
  1438. this.myGroup = new FormGroup({
  1439. cities: this.cityArray
  1440. });`;
  1441. const ngModelGroupExample = `
  1442. <form>
  1443. <div ngModelGroup="person">
  1444. <input [(ngModel)]="person.name" name="firstName">
  1445. </div>
  1446. </form>`;
  1447. const ngModelWithFormGroupExample = `
  1448. <div [formGroup]="myGroup">
  1449. <input formControlName="firstName">
  1450. <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
  1451. </div>
  1452. `;
  1453. function controlParentException(nameOrIndex) {
  1454. return new _RuntimeError(1050 /* RuntimeErrorCode.FORM_CONTROL_NAME_MISSING_PARENT */, `formControlName must be used with a parent formGroup directive. You'll want to add a formGroup
  1455. directive and pass it an existing FormGroup instance (you can create one in your class).
  1456. ${describeFormControl(nameOrIndex)}
  1457. Example:
  1458. ${formControlNameExample}`);
  1459. }
  1460. function describeFormControl(nameOrIndex) {
  1461. if (nameOrIndex == null || nameOrIndex === '') {
  1462. return '';
  1463. }
  1464. const valueType = typeof nameOrIndex === 'string' ? 'name' : 'index';
  1465. return `Affected Form Control ${valueType}: "${nameOrIndex}"`;
  1466. }
  1467. function ngModelGroupException() {
  1468. return new _RuntimeError(1051 /* RuntimeErrorCode.FORM_CONTROL_NAME_INSIDE_MODEL_GROUP */, `formControlName cannot be used with an ngModelGroup parent. It is only compatible with parents
  1469. that also have a "form" prefix: formGroupName, formArrayName, or formGroup.
  1470. Option 1: Update the parent to be formGroupName (reactive form strategy)
  1471. ${formGroupNameExample}
  1472. Option 2: Use ngModel instead of formControlName (template-driven strategy)
  1473. ${ngModelGroupExample}`);
  1474. }
  1475. function missingFormException() {
  1476. return new _RuntimeError(1052 /* RuntimeErrorCode.FORM_GROUP_MISSING_INSTANCE */, `formGroup expects a FormGroup instance. Please pass one in.
  1477. Example:
  1478. ${formControlNameExample}`);
  1479. }
  1480. function groupParentException() {
  1481. return new _RuntimeError(1053 /* RuntimeErrorCode.FORM_GROUP_NAME_MISSING_PARENT */, `formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup
  1482. directive and pass it an existing FormGroup instance (you can create one in your class).
  1483. Example:
  1484. ${formGroupNameExample}`);
  1485. }
  1486. function arrayParentException() {
  1487. return new _RuntimeError(1054 /* RuntimeErrorCode.FORM_ARRAY_NAME_MISSING_PARENT */, `formArrayName must be used with a parent formGroup directive. You'll want to add a formGroup
  1488. directive and pass it an existing FormGroup instance (you can create one in your class).
  1489. Example:
  1490. ${formArrayNameExample}`);
  1491. }
  1492. const disabledAttrWarning = `
  1493. It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
  1494. when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
  1495. you. We recommend using this approach to avoid 'changed after checked' errors.
  1496. Example:
  1497. // Specify the \`disabled\` property at control creation time:
  1498. form = new FormGroup({
  1499. first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
  1500. last: new FormControl('Drew', Validators.required)
  1501. });
  1502. // Controls can also be enabled/disabled after creation:
  1503. form.get('first')?.enable();
  1504. form.get('last')?.disable();
  1505. `;
  1506. const asyncValidatorsDroppedWithOptsWarning = `
  1507. It looks like you're constructing using a FormControl with both an options argument and an
  1508. async validators argument. Mixing these arguments will cause your async validators to be dropped.
  1509. You should either put all your validators in the options object, or in separate validators
  1510. arguments. For example:
  1511. // Using validators arguments
  1512. fc = new FormControl(42, Validators.required, myAsyncValidator);
  1513. // Using AbstractControlOptions
  1514. fc = new FormControl(42, {validators: Validators.required, asyncValidators: myAV});
  1515. // Do NOT mix them: async validators will be dropped!
  1516. fc = new FormControl(42, {validators: Validators.required}, /* Oops! */ myAsyncValidator);
  1517. `;
  1518. function ngModelWarning(directiveName) {
  1519. return `
  1520. It looks like you're using ngModel on the same form field as ${directiveName}.
  1521. Support for using the ngModel input property and ngModelChange event with
  1522. reactive form directives has been deprecated in Angular v6 and will be removed
  1523. in a future version of Angular.
  1524. For more information on this, see our API docs here:
  1525. https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective' : 'FormControlName'}#use-with-ngmodel
  1526. `;
  1527. }
  1528. function describeKey(isFormGroup, key) {
  1529. return isFormGroup ? `with name: '${key}'` : `at index: ${key}`;
  1530. }
  1531. function noControlsError(isFormGroup) {
  1532. return `
  1533. There are no form controls registered with this ${isFormGroup ? 'group' : 'array'} yet. If you're using ngModel,
  1534. you may want to check next tick (e.g. use setTimeout).
  1535. `;
  1536. }
  1537. function missingControlError(isFormGroup, key) {
  1538. return `Cannot find form control ${describeKey(isFormGroup, key)}`;
  1539. }
  1540. function missingControlValueError(isFormGroup, key) {
  1541. return `Must supply a value for form control ${describeKey(isFormGroup, key)}`;
  1542. }
  1543. /**
  1544. * Reports that a control is valid, meaning that no errors exist in the input value.
  1545. *
  1546. * @see {@link status}
  1547. */
  1548. const VALID = 'VALID';
  1549. /**
  1550. * Reports that a control is invalid, meaning that an error exists in the input value.
  1551. *
  1552. * @see {@link status}
  1553. */
  1554. const INVALID = 'INVALID';
  1555. /**
  1556. * Reports that a control is pending, meaning that async validation is occurring and
  1557. * errors are not yet available for the input value.
  1558. *
  1559. * @see {@link markAsPending}
  1560. * @see {@link status}
  1561. */
  1562. const PENDING = 'PENDING';
  1563. /**
  1564. * Reports that a control is disabled, meaning that the control is exempt from ancestor
  1565. * calculations of validity or value.
  1566. *
  1567. * @see {@link markAsDisabled}
  1568. * @see {@link status}
  1569. */
  1570. const DISABLED = 'DISABLED';
  1571. /**
  1572. * Base class for every event sent by `AbstractControl.events()`
  1573. *
  1574. * @publicApi
  1575. */
  1576. class ControlEvent {
  1577. }
  1578. /**
  1579. * Event fired when the value of a control changes.
  1580. *
  1581. * @publicApi
  1582. */
  1583. class ValueChangeEvent extends ControlEvent {
  1584. value;
  1585. source;
  1586. constructor(value, source) {
  1587. super();
  1588. this.value = value;
  1589. this.source = source;
  1590. }
  1591. }
  1592. /**
  1593. * Event fired when the control's pristine state changes (pristine <=> dirty).
  1594. *
  1595. * @publicApi */
  1596. class PristineChangeEvent extends ControlEvent {
  1597. pristine;
  1598. source;
  1599. constructor(pristine, source) {
  1600. super();
  1601. this.pristine = pristine;
  1602. this.source = source;
  1603. }
  1604. }
  1605. /**
  1606. * Event fired when the control's touched status changes (touched <=> untouched).
  1607. *
  1608. * @publicApi
  1609. */
  1610. class TouchedChangeEvent extends ControlEvent {
  1611. touched;
  1612. source;
  1613. constructor(touched, source) {
  1614. super();
  1615. this.touched = touched;
  1616. this.source = source;
  1617. }
  1618. }
  1619. /**
  1620. * Event fired when the control's status changes.
  1621. *
  1622. * @publicApi
  1623. */
  1624. class StatusChangeEvent extends ControlEvent {
  1625. status;
  1626. source;
  1627. constructor(status, source) {
  1628. super();
  1629. this.status = status;
  1630. this.source = source;
  1631. }
  1632. }
  1633. /**
  1634. * Event fired when a form is submitted
  1635. *
  1636. * @publicApi
  1637. */
  1638. class FormSubmittedEvent extends ControlEvent {
  1639. source;
  1640. constructor(source) {
  1641. super();
  1642. this.source = source;
  1643. }
  1644. }
  1645. /**
  1646. * Event fired when a form is reset.
  1647. *
  1648. * @publicApi
  1649. */
  1650. class FormResetEvent extends ControlEvent {
  1651. source;
  1652. constructor(source) {
  1653. super();
  1654. this.source = source;
  1655. }
  1656. }
  1657. /**
  1658. * Gets validators from either an options object or given validators.
  1659. */
  1660. function pickValidators(validatorOrOpts) {
  1661. return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.validators : validatorOrOpts) || null;
  1662. }
  1663. /**
  1664. * Creates validator function by combining provided validators.
  1665. */
  1666. function coerceToValidator(validator) {
  1667. return Array.isArray(validator) ? composeValidators(validator) : validator || null;
  1668. }
  1669. /**
  1670. * Gets async validators from either an options object or given validators.
  1671. */
  1672. function pickAsyncValidators(asyncValidator, validatorOrOpts) {
  1673. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  1674. if (isOptionsObj(validatorOrOpts) && asyncValidator) {
  1675. console.warn(asyncValidatorsDroppedWithOptsWarning);
  1676. }
  1677. }
  1678. return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.asyncValidators : asyncValidator) || null;
  1679. }
  1680. /**
  1681. * Creates async validator function by combining provided async validators.
  1682. */
  1683. function coerceToAsyncValidator(asyncValidator) {
  1684. return Array.isArray(asyncValidator)
  1685. ? composeAsyncValidators(asyncValidator)
  1686. : asyncValidator || null;
  1687. }
  1688. function isOptionsObj(validatorOrOpts) {
  1689. return (validatorOrOpts != null &&
  1690. !Array.isArray(validatorOrOpts) &&
  1691. typeof validatorOrOpts === 'object');
  1692. }
  1693. function assertControlPresent(parent, isGroup, key) {
  1694. const controls = parent.controls;
  1695. const collection = isGroup ? Object.keys(controls) : controls;
  1696. if (!collection.length) {
  1697. throw new _RuntimeError(1000 /* RuntimeErrorCode.NO_CONTROLS */, typeof ngDevMode === 'undefined' || ngDevMode ? noControlsError(isGroup) : '');
  1698. }
  1699. if (!controls[key]) {
  1700. throw new _RuntimeError(1001 /* RuntimeErrorCode.MISSING_CONTROL */, typeof ngDevMode === 'undefined' || ngDevMode ? missingControlError(isGroup, key) : '');
  1701. }
  1702. }
  1703. function assertAllValuesPresent(control, isGroup, value) {
  1704. control._forEachChild((_, key) => {
  1705. if (value[key] === undefined) {
  1706. throw new _RuntimeError(1002 /* RuntimeErrorCode.MISSING_CONTROL_VALUE */, typeof ngDevMode === 'undefined' || ngDevMode ? missingControlValueError(isGroup, key) : '');
  1707. }
  1708. });
  1709. }
  1710. /**
  1711. * This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
  1712. *
  1713. * It provides some of the shared behavior that all controls and groups of controls have, like
  1714. * running validators, calculating status, and resetting state. It also defines the properties
  1715. * that are shared between all sub-classes, like `value`, `valid`, and `dirty`. It shouldn't be
  1716. * instantiated directly.
  1717. *
  1718. * The first type parameter TValue represents the value type of the control (`control.value`).
  1719. * The optional type parameter TRawValue represents the raw value type (`control.getRawValue()`).
  1720. *
  1721. * @see [Forms Guide](guide/forms)
  1722. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  1723. * @see [Dynamic Forms Guide](guide/forms/dynamic-forms)
  1724. *
  1725. * @publicApi
  1726. */
  1727. class AbstractControl {
  1728. /** @internal */
  1729. _pendingDirty = false;
  1730. /**
  1731. * Indicates that a control has its own pending asynchronous validation in progress.
  1732. * It also stores if the control should emit events when the validation status changes.
  1733. *
  1734. * @internal
  1735. */
  1736. _hasOwnPendingAsyncValidator = null;
  1737. /** @internal */
  1738. _pendingTouched = false;
  1739. /** @internal */
  1740. _onCollectionChange = () => { };
  1741. /** @internal */
  1742. _updateOn;
  1743. _parent = null;
  1744. _asyncValidationSubscription;
  1745. /**
  1746. * Contains the result of merging synchronous validators into a single validator function
  1747. * (combined using `Validators.compose`).
  1748. *
  1749. * @internal
  1750. */
  1751. _composedValidatorFn;
  1752. /**
  1753. * Contains the result of merging asynchronous validators into a single validator function
  1754. * (combined using `Validators.composeAsync`).
  1755. *
  1756. * @internal
  1757. */
  1758. _composedAsyncValidatorFn;
  1759. /**
  1760. * Synchronous validators as they were provided:
  1761. * - in `AbstractControl` constructor
  1762. * - as an argument while calling `setValidators` function
  1763. * - while calling the setter on the `validator` field (e.g. `control.validator = validatorFn`)
  1764. *
  1765. * @internal
  1766. */
  1767. _rawValidators;
  1768. /**
  1769. * Asynchronous validators as they were provided:
  1770. * - in `AbstractControl` constructor
  1771. * - as an argument while calling `setAsyncValidators` function
  1772. * - while calling the setter on the `asyncValidator` field (e.g. `control.asyncValidator =
  1773. * asyncValidatorFn`)
  1774. *
  1775. * @internal
  1776. */
  1777. _rawAsyncValidators;
  1778. /**
  1779. * The current value of the control.
  1780. *
  1781. * * For a `FormControl`, the current value.
  1782. * * For an enabled `FormGroup`, the values of enabled controls as an object
  1783. * with a key-value pair for each member of the group.
  1784. * * For a disabled `FormGroup`, the values of all controls as an object
  1785. * with a key-value pair for each member of the group.
  1786. * * For a `FormArray`, the values of enabled controls as an array.
  1787. *
  1788. */
  1789. value;
  1790. /**
  1791. * Initialize the AbstractControl instance.
  1792. *
  1793. * @param validators The function or array of functions that is used to determine the validity of
  1794. * this control synchronously.
  1795. * @param asyncValidators The function or array of functions that is used to determine validity of
  1796. * this control asynchronously.
  1797. */
  1798. constructor(validators, asyncValidators) {
  1799. this._assignValidators(validators);
  1800. this._assignAsyncValidators(asyncValidators);
  1801. }
  1802. /**
  1803. * Returns the function that is used to determine the validity of this control synchronously.
  1804. * If multiple validators have been added, this will be a single composed function.
  1805. * See `Validators.compose()` for additional information.
  1806. */
  1807. get validator() {
  1808. return this._composedValidatorFn;
  1809. }
  1810. set validator(validatorFn) {
  1811. this._rawValidators = this._composedValidatorFn = validatorFn;
  1812. }
  1813. /**
  1814. * Returns the function that is used to determine the validity of this control asynchronously.
  1815. * If multiple validators have been added, this will be a single composed function.
  1816. * See `Validators.compose()` for additional information.
  1817. */
  1818. get asyncValidator() {
  1819. return this._composedAsyncValidatorFn;
  1820. }
  1821. set asyncValidator(asyncValidatorFn) {
  1822. this._rawAsyncValidators = this._composedAsyncValidatorFn = asyncValidatorFn;
  1823. }
  1824. /**
  1825. * The parent control.
  1826. */
  1827. get parent() {
  1828. return this._parent;
  1829. }
  1830. /**
  1831. * The validation status of the control.
  1832. *
  1833. * @see {@link FormControlStatus}
  1834. *
  1835. * These status values are mutually exclusive, so a control cannot be
  1836. * both valid AND invalid or invalid AND disabled.
  1837. */
  1838. get status() {
  1839. return untracked(this.statusReactive);
  1840. }
  1841. set status(v) {
  1842. untracked(() => this.statusReactive.set(v));
  1843. }
  1844. /** @internal */
  1845. _status = computed(() => this.statusReactive());
  1846. statusReactive = signal(undefined);
  1847. /**
  1848. * A control is `valid` when its `status` is `VALID`.
  1849. *
  1850. * @see {@link AbstractControl.status}
  1851. *
  1852. * @returns True if the control has passed all of its validation tests,
  1853. * false otherwise.
  1854. */
  1855. get valid() {
  1856. return this.status === VALID;
  1857. }
  1858. /**
  1859. * A control is `invalid` when its `status` is `INVALID`.
  1860. *
  1861. * @see {@link AbstractControl.status}
  1862. *
  1863. * @returns True if this control has failed one or more of its validation checks,
  1864. * false otherwise.
  1865. */
  1866. get invalid() {
  1867. return this.status === INVALID;
  1868. }
  1869. /**
  1870. * A control is `pending` when its `status` is `PENDING`.
  1871. *
  1872. * @see {@link AbstractControl.status}
  1873. *
  1874. * @returns True if this control is in the process of conducting a validation check,
  1875. * false otherwise.
  1876. */
  1877. get pending() {
  1878. return this.status == PENDING;
  1879. }
  1880. /**
  1881. * A control is `disabled` when its `status` is `DISABLED`.
  1882. *
  1883. * Disabled controls are exempt from validation checks and
  1884. * are not included in the aggregate value of their ancestor
  1885. * controls.
  1886. *
  1887. * @see {@link AbstractControl.status}
  1888. *
  1889. * @returns True if the control is disabled, false otherwise.
  1890. */
  1891. get disabled() {
  1892. return this.status === DISABLED;
  1893. }
  1894. /**
  1895. * A control is `enabled` as long as its `status` is not `DISABLED`.
  1896. *
  1897. * @returns True if the control has any status other than 'DISABLED',
  1898. * false if the status is 'DISABLED'.
  1899. *
  1900. * @see {@link AbstractControl.status}
  1901. *
  1902. */
  1903. get enabled() {
  1904. return this.status !== DISABLED;
  1905. }
  1906. /**
  1907. * An object containing any errors generated by failing validation,
  1908. * or null if there are no errors.
  1909. */
  1910. errors;
  1911. /**
  1912. * A control is `pristine` if the user has not yet changed
  1913. * the value in the UI.
  1914. *
  1915. * @returns True if the user has not yet changed the value in the UI; compare `dirty`.
  1916. * Programmatic changes to a control's value do not mark it dirty.
  1917. */
  1918. get pristine() {
  1919. return untracked(this.pristineReactive);
  1920. }
  1921. set pristine(v) {
  1922. untracked(() => this.pristineReactive.set(v));
  1923. }
  1924. /** @internal */
  1925. _pristine = computed(() => this.pristineReactive());
  1926. pristineReactive = signal(true);
  1927. /**
  1928. * A control is `dirty` if the user has changed the value
  1929. * in the UI.
  1930. *
  1931. * @returns True if the user has changed the value of this control in the UI; compare `pristine`.
  1932. * Programmatic changes to a control's value do not mark it dirty.
  1933. */
  1934. get dirty() {
  1935. return !this.pristine;
  1936. }
  1937. /**
  1938. * True if the control is marked as `touched`.
  1939. *
  1940. * A control is marked `touched` once the user has triggered
  1941. * a `blur` event on it.
  1942. */
  1943. get touched() {
  1944. return untracked(this.touchedReactive);
  1945. }
  1946. set touched(v) {
  1947. untracked(() => this.touchedReactive.set(v));
  1948. }
  1949. /** @internal */
  1950. _touched = computed(() => this.touchedReactive());
  1951. touchedReactive = signal(false);
  1952. /**
  1953. * True if the control has not been marked as touched
  1954. *
  1955. * A control is `untouched` if the user has not yet triggered
  1956. * a `blur` event on it.
  1957. */
  1958. get untouched() {
  1959. return !this.touched;
  1960. }
  1961. /**
  1962. * Exposed as observable, see below.
  1963. *
  1964. * @internal
  1965. */
  1966. _events = new Subject();
  1967. /**
  1968. * A multicasting observable that emits an event every time the state of the control changes.
  1969. * It emits for value, status, pristine or touched changes.
  1970. *
  1971. * **Note**: On value change, the emit happens right after a value of this control is updated. The
  1972. * value of a parent control (for example if this FormControl is a part of a FormGroup) is updated
  1973. * later, so accessing a value of a parent control (using the `value` property) from the callback
  1974. * of this event might result in getting a value that has not been updated yet. Subscribe to the
  1975. * `events` of the parent control instead.
  1976. * For other event types, the events are emitted after the parent control has been updated.
  1977. *
  1978. */
  1979. events = this._events.asObservable();
  1980. /**
  1981. * A multicasting observable that emits an event every time the value of the control changes, in
  1982. * the UI or programmatically. It also emits an event each time you call enable() or disable()
  1983. * without passing along {emitEvent: false} as a function argument.
  1984. *
  1985. * **Note**: the emit happens right after a value of this control is updated. The value of a
  1986. * parent control (for example if this FormControl is a part of a FormGroup) is updated later, so
  1987. * accessing a value of a parent control (using the `value` property) from the callback of this
  1988. * event might result in getting a value that has not been updated yet. Subscribe to the
  1989. * `valueChanges` event of the parent control instead.
  1990. */
  1991. valueChanges;
  1992. /**
  1993. * A multicasting observable that emits an event every time the validation `status` of the control
  1994. * recalculates.
  1995. *
  1996. * @see {@link FormControlStatus}
  1997. * @see {@link AbstractControl.status}
  1998. */
  1999. statusChanges;
  2000. /**
  2001. * Reports the update strategy of the `AbstractControl` (meaning
  2002. * the event on which the control updates itself).
  2003. * Possible values: `'change'` | `'blur'` | `'submit'`
  2004. * Default value: `'change'`
  2005. */
  2006. get updateOn() {
  2007. return this._updateOn ? this._updateOn : this.parent ? this.parent.updateOn : 'change';
  2008. }
  2009. /**
  2010. * Sets the synchronous validators that are active on this control. Calling
  2011. * this overwrites any existing synchronous validators.
  2012. *
  2013. * When you add or remove a validator at run time, you must call
  2014. * `updateValueAndValidity()` for the new validation to take effect.
  2015. *
  2016. * If you want to add a new validator without affecting existing ones, consider
  2017. * using `addValidators()` method instead.
  2018. */
  2019. setValidators(validators) {
  2020. this._assignValidators(validators);
  2021. }
  2022. /**
  2023. * Sets the asynchronous validators that are active on this control. Calling this
  2024. * overwrites any existing asynchronous validators.
  2025. *
  2026. * When you add or remove a validator at run time, you must call
  2027. * `updateValueAndValidity()` for the new validation to take effect.
  2028. *
  2029. * If you want to add a new validator without affecting existing ones, consider
  2030. * using `addAsyncValidators()` method instead.
  2031. */
  2032. setAsyncValidators(validators) {
  2033. this._assignAsyncValidators(validators);
  2034. }
  2035. /**
  2036. * Add a synchronous validator or validators to this control, without affecting other validators.
  2037. *
  2038. * When you add or remove a validator at run time, you must call
  2039. * `updateValueAndValidity()` for the new validation to take effect.
  2040. *
  2041. * Adding a validator that already exists will have no effect. If duplicate validator functions
  2042. * are present in the `validators` array, only the first instance would be added to a form
  2043. * control.
  2044. *
  2045. * @param validators The new validator function or functions to add to this control.
  2046. */
  2047. addValidators(validators) {
  2048. this.setValidators(addValidators(validators, this._rawValidators));
  2049. }
  2050. /**
  2051. * Add an asynchronous validator or validators to this control, without affecting other
  2052. * validators.
  2053. *
  2054. * When you add or remove a validator at run time, you must call
  2055. * `updateValueAndValidity()` for the new validation to take effect.
  2056. *
  2057. * Adding a validator that already exists will have no effect.
  2058. *
  2059. * @param validators The new asynchronous validator function or functions to add to this control.
  2060. */
  2061. addAsyncValidators(validators) {
  2062. this.setAsyncValidators(addValidators(validators, this._rawAsyncValidators));
  2063. }
  2064. /**
  2065. * Remove a synchronous validator from this control, without affecting other validators.
  2066. * Validators are compared by function reference; you must pass a reference to the exact same
  2067. * validator function as the one that was originally set. If a provided validator is not found,
  2068. * it is ignored.
  2069. *
  2070. * @usageNotes
  2071. *
  2072. * ### Reference to a ValidatorFn
  2073. *
  2074. * ```
  2075. * // Reference to the RequiredValidator
  2076. * const ctrl = new FormControl<string | null>('', Validators.required);
  2077. * ctrl.removeValidators(Validators.required);
  2078. *
  2079. * // Reference to anonymous function inside MinValidator
  2080. * const minValidator = Validators.min(3);
  2081. * const ctrl = new FormControl<string | null>('', minValidator);
  2082. * expect(ctrl.hasValidator(minValidator)).toEqual(true)
  2083. * expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
  2084. *
  2085. * ctrl.removeValidators(minValidator);
  2086. * ```
  2087. *
  2088. * When you add or remove a validator at run time, you must call
  2089. * `updateValueAndValidity()` for the new validation to take effect.
  2090. *
  2091. * @param validators The validator or validators to remove.
  2092. */
  2093. removeValidators(validators) {
  2094. this.setValidators(removeValidators(validators, this._rawValidators));
  2095. }
  2096. /**
  2097. * Remove an asynchronous validator from this control, without affecting other validators.
  2098. * Validators are compared by function reference; you must pass a reference to the exact same
  2099. * validator function as the one that was originally set. If a provided validator is not found, it
  2100. * is ignored.
  2101. *
  2102. * When you add or remove a validator at run time, you must call
  2103. * `updateValueAndValidity()` for the new validation to take effect.
  2104. *
  2105. * @param validators The asynchronous validator or validators to remove.
  2106. */
  2107. removeAsyncValidators(validators) {
  2108. this.setAsyncValidators(removeValidators(validators, this._rawAsyncValidators));
  2109. }
  2110. /**
  2111. * Check whether a synchronous validator function is present on this control. The provided
  2112. * validator must be a reference to the exact same function that was provided.
  2113. *
  2114. * @usageNotes
  2115. *
  2116. * ### Reference to a ValidatorFn
  2117. *
  2118. * ```
  2119. * // Reference to the RequiredValidator
  2120. * const ctrl = new FormControl<number | null>(0, Validators.required);
  2121. * expect(ctrl.hasValidator(Validators.required)).toEqual(true)
  2122. *
  2123. * // Reference to anonymous function inside MinValidator
  2124. * const minValidator = Validators.min(3);
  2125. * const ctrl = new FormControl<number | null>(0, minValidator);
  2126. * expect(ctrl.hasValidator(minValidator)).toEqual(true)
  2127. * expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
  2128. * ```
  2129. *
  2130. * @param validator The validator to check for presence. Compared by function reference.
  2131. * @returns Whether the provided validator was found on this control.
  2132. */
  2133. hasValidator(validator) {
  2134. return hasValidator(this._rawValidators, validator);
  2135. }
  2136. /**
  2137. * Check whether an asynchronous validator function is present on this control. The provided
  2138. * validator must be a reference to the exact same function that was provided.
  2139. *
  2140. * @param validator The asynchronous validator to check for presence. Compared by function
  2141. * reference.
  2142. * @returns Whether the provided asynchronous validator was found on this control.
  2143. */
  2144. hasAsyncValidator(validator) {
  2145. return hasValidator(this._rawAsyncValidators, validator);
  2146. }
  2147. /**
  2148. * Empties out the synchronous validator list.
  2149. *
  2150. * When you add or remove a validator at run time, you must call
  2151. * `updateValueAndValidity()` for the new validation to take effect.
  2152. *
  2153. */
  2154. clearValidators() {
  2155. this.validator = null;
  2156. }
  2157. /**
  2158. * Empties out the async validator list.
  2159. *
  2160. * When you add or remove a validator at run time, you must call
  2161. * `updateValueAndValidity()` for the new validation to take effect.
  2162. *
  2163. */
  2164. clearAsyncValidators() {
  2165. this.asyncValidator = null;
  2166. }
  2167. markAsTouched(opts = {}) {
  2168. const changed = this.touched === false;
  2169. this.touched = true;
  2170. const sourceControl = opts.sourceControl ?? this;
  2171. if (this._parent && !opts.onlySelf) {
  2172. this._parent.markAsTouched({ ...opts, sourceControl });
  2173. }
  2174. if (changed && opts.emitEvent !== false) {
  2175. this._events.next(new TouchedChangeEvent(true, sourceControl));
  2176. }
  2177. }
  2178. /**
  2179. * Marks the control and all its descendant controls as `touched`.
  2180. * @see {@link markAsTouched()}
  2181. *
  2182. * @param opts Configuration options that determine how the control propagates changes
  2183. * and emits events after marking is applied.
  2184. * * `emitEvent`: When true or not supplied (the default), the `events`
  2185. * observable emits a `TouchedChangeEvent` with the `touched` property being `true`.
  2186. * When false, no events are emitted.
  2187. */
  2188. markAllAsTouched(opts = {}) {
  2189. this.markAsTouched({ onlySelf: true, emitEvent: opts.emitEvent, sourceControl: this });
  2190. this._forEachChild((control) => control.markAllAsTouched(opts));
  2191. }
  2192. markAsUntouched(opts = {}) {
  2193. const changed = this.touched === true;
  2194. this.touched = false;
  2195. this._pendingTouched = false;
  2196. const sourceControl = opts.sourceControl ?? this;
  2197. this._forEachChild((control) => {
  2198. control.markAsUntouched({ onlySelf: true, emitEvent: opts.emitEvent, sourceControl });
  2199. });
  2200. if (this._parent && !opts.onlySelf) {
  2201. this._parent._updateTouched(opts, sourceControl);
  2202. }
  2203. if (changed && opts.emitEvent !== false) {
  2204. this._events.next(new TouchedChangeEvent(false, sourceControl));
  2205. }
  2206. }
  2207. markAsDirty(opts = {}) {
  2208. const changed = this.pristine === true;
  2209. this.pristine = false;
  2210. const sourceControl = opts.sourceControl ?? this;
  2211. if (this._parent && !opts.onlySelf) {
  2212. this._parent.markAsDirty({ ...opts, sourceControl });
  2213. }
  2214. if (changed && opts.emitEvent !== false) {
  2215. this._events.next(new PristineChangeEvent(false, sourceControl));
  2216. }
  2217. }
  2218. markAsPristine(opts = {}) {
  2219. const changed = this.pristine === false;
  2220. this.pristine = true;
  2221. this._pendingDirty = false;
  2222. const sourceControl = opts.sourceControl ?? this;
  2223. this._forEachChild((control) => {
  2224. /** We don't propagate the source control downwards */
  2225. control.markAsPristine({ onlySelf: true, emitEvent: opts.emitEvent });
  2226. });
  2227. if (this._parent && !opts.onlySelf) {
  2228. this._parent._updatePristine(opts, sourceControl);
  2229. }
  2230. if (changed && opts.emitEvent !== false) {
  2231. this._events.next(new PristineChangeEvent(true, sourceControl));
  2232. }
  2233. }
  2234. markAsPending(opts = {}) {
  2235. this.status = PENDING;
  2236. const sourceControl = opts.sourceControl ?? this;
  2237. if (opts.emitEvent !== false) {
  2238. this._events.next(new StatusChangeEvent(this.status, sourceControl));
  2239. this.statusChanges.emit(this.status);
  2240. }
  2241. if (this._parent && !opts.onlySelf) {
  2242. this._parent.markAsPending({ ...opts, sourceControl });
  2243. }
  2244. }
  2245. disable(opts = {}) {
  2246. // If parent has been marked artificially dirty we don't want to re-calculate the
  2247. // parent's dirtiness based on the children.
  2248. const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
  2249. this.status = DISABLED;
  2250. this.errors = null;
  2251. this._forEachChild((control) => {
  2252. /** We don't propagate the source control downwards */
  2253. control.disable({ ...opts, onlySelf: true });
  2254. });
  2255. this._updateValue();
  2256. const sourceControl = opts.sourceControl ?? this;
  2257. if (opts.emitEvent !== false) {
  2258. this._events.next(new ValueChangeEvent(this.value, sourceControl));
  2259. this._events.next(new StatusChangeEvent(this.status, sourceControl));
  2260. this.valueChanges.emit(this.value);
  2261. this.statusChanges.emit(this.status);
  2262. }
  2263. this._updateAncestors({ ...opts, skipPristineCheck }, this);
  2264. this._onDisabledChange.forEach((changeFn) => changeFn(true));
  2265. }
  2266. /**
  2267. * Enables the control. This means the control is included in validation checks and
  2268. * the aggregate value of its parent. Its status recalculates based on its value and
  2269. * its validators.
  2270. *
  2271. * By default, if the control has children, all children are enabled.
  2272. *
  2273. * @see {@link AbstractControl.status}
  2274. *
  2275. * @param opts Configure options that control how the control propagates changes and
  2276. * emits events when marked as untouched
  2277. * * `onlySelf`: When true, mark only this control. When false or not supplied,
  2278. * marks all direct ancestors. Default is false.
  2279. * * `emitEvent`: When true or not supplied (the default), the `statusChanges`,
  2280. * `valueChanges` and `events`
  2281. * observables emit events with the latest status and value when the control is enabled.
  2282. * When false, no events are emitted.
  2283. */
  2284. enable(opts = {}) {
  2285. // If parent has been marked artificially dirty we don't want to re-calculate the
  2286. // parent's dirtiness based on the children.
  2287. const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
  2288. this.status = VALID;
  2289. this._forEachChild((control) => {
  2290. control.enable({ ...opts, onlySelf: true });
  2291. });
  2292. this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
  2293. this._updateAncestors({ ...opts, skipPristineCheck }, this);
  2294. this._onDisabledChange.forEach((changeFn) => changeFn(false));
  2295. }
  2296. _updateAncestors(opts, sourceControl) {
  2297. if (this._parent && !opts.onlySelf) {
  2298. this._parent.updateValueAndValidity(opts);
  2299. if (!opts.skipPristineCheck) {
  2300. this._parent._updatePristine({}, sourceControl);
  2301. }
  2302. this._parent._updateTouched({}, sourceControl);
  2303. }
  2304. }
  2305. /**
  2306. * Sets the parent of the control
  2307. *
  2308. * @param parent The new parent.
  2309. */
  2310. setParent(parent) {
  2311. this._parent = parent;
  2312. }
  2313. /**
  2314. * The raw value of this control. For most control implementations, the raw value will include
  2315. * disabled children.
  2316. */
  2317. getRawValue() {
  2318. return this.value;
  2319. }
  2320. updateValueAndValidity(opts = {}) {
  2321. this._setInitialStatus();
  2322. this._updateValue();
  2323. if (this.enabled) {
  2324. const shouldHaveEmitted = this._cancelExistingSubscription();
  2325. this.errors = this._runValidator();
  2326. this.status = this._calculateStatus();
  2327. if (this.status === VALID || this.status === PENDING) {
  2328. // If the canceled subscription should have emitted
  2329. // we make sure the async validator emits the status change on completion
  2330. this._runAsyncValidator(shouldHaveEmitted, opts.emitEvent);
  2331. }
  2332. }
  2333. const sourceControl = opts.sourceControl ?? this;
  2334. if (opts.emitEvent !== false) {
  2335. this._events.next(new ValueChangeEvent(this.value, sourceControl));
  2336. this._events.next(new StatusChangeEvent(this.status, sourceControl));
  2337. this.valueChanges.emit(this.value);
  2338. this.statusChanges.emit(this.status);
  2339. }
  2340. if (this._parent && !opts.onlySelf) {
  2341. this._parent.updateValueAndValidity({ ...opts, sourceControl });
  2342. }
  2343. }
  2344. /** @internal */
  2345. _updateTreeValidity(opts = { emitEvent: true }) {
  2346. this._forEachChild((ctrl) => ctrl._updateTreeValidity(opts));
  2347. this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
  2348. }
  2349. _setInitialStatus() {
  2350. this.status = this._allControlsDisabled() ? DISABLED : VALID;
  2351. }
  2352. _runValidator() {
  2353. return this.validator ? this.validator(this) : null;
  2354. }
  2355. _runAsyncValidator(shouldHaveEmitted, emitEvent) {
  2356. if (this.asyncValidator) {
  2357. this.status = PENDING;
  2358. this._hasOwnPendingAsyncValidator = { emitEvent: emitEvent !== false };
  2359. const obs = toObservable(this.asyncValidator(this));
  2360. this._asyncValidationSubscription = obs.subscribe((errors) => {
  2361. this._hasOwnPendingAsyncValidator = null;
  2362. // This will trigger the recalculation of the validation status, which depends on
  2363. // the state of the asynchronous validation (whether it is in progress or not). So, it is
  2364. // necessary that we have updated the `_hasOwnPendingAsyncValidator` boolean flag first.
  2365. this.setErrors(errors, { emitEvent, shouldHaveEmitted });
  2366. });
  2367. }
  2368. }
  2369. _cancelExistingSubscription() {
  2370. if (this._asyncValidationSubscription) {
  2371. this._asyncValidationSubscription.unsubscribe();
  2372. // we're cancelling the validator subscribtion, we keep if it should have emitted
  2373. // because we want to emit eventually if it was required at least once.
  2374. const shouldHaveEmitted = this._hasOwnPendingAsyncValidator?.emitEvent ?? false;
  2375. this._hasOwnPendingAsyncValidator = null;
  2376. return shouldHaveEmitted;
  2377. }
  2378. return false;
  2379. }
  2380. setErrors(errors, opts = {}) {
  2381. this.errors = errors;
  2382. this._updateControlsErrors(opts.emitEvent !== false, this, opts.shouldHaveEmitted);
  2383. }
  2384. /**
  2385. * Retrieves a child control given the control's name or path.
  2386. *
  2387. * @param path A dot-delimited string or array of string/number values that define the path to the
  2388. * control. If a string is provided, passing it as a string literal will result in improved type
  2389. * information. Likewise, if an array is provided, passing it `as const` will cause improved type
  2390. * information to be available.
  2391. *
  2392. * @usageNotes
  2393. * ### Retrieve a nested control
  2394. *
  2395. * For example, to get a `name` control nested within a `person` sub-group:
  2396. *
  2397. * * `this.form.get('person.name');`
  2398. *
  2399. * -OR-
  2400. *
  2401. * * `this.form.get(['person', 'name'] as const);` // `as const` gives improved typings
  2402. *
  2403. * ### Retrieve a control in a FormArray
  2404. *
  2405. * When accessing an element inside a FormArray, you can use an element index.
  2406. * For example, to get a `price` control from the first element in an `items` array you can use:
  2407. *
  2408. * * `this.form.get('items.0.price');`
  2409. *
  2410. * -OR-
  2411. *
  2412. * * `this.form.get(['items', 0, 'price']);`
  2413. */
  2414. get(path) {
  2415. let currPath = path;
  2416. if (currPath == null)
  2417. return null;
  2418. if (!Array.isArray(currPath))
  2419. currPath = currPath.split('.');
  2420. if (currPath.length === 0)
  2421. return null;
  2422. return currPath.reduce((control, name) => control && control._find(name), this);
  2423. }
  2424. /**
  2425. * @description
  2426. * Reports error data for the control with the given path.
  2427. *
  2428. * @param errorCode The code of the error to check
  2429. * @param path A list of control names that designates how to move from the current control
  2430. * to the control that should be queried for errors.
  2431. *
  2432. * @usageNotes
  2433. * For example, for the following `FormGroup`:
  2434. *
  2435. * ```ts
  2436. * form = new FormGroup({
  2437. * address: new FormGroup({ street: new FormControl() })
  2438. * });
  2439. * ```
  2440. *
  2441. * The path to the 'street' control from the root form would be 'address' -> 'street'.
  2442. *
  2443. * It can be provided to this method in one of two formats:
  2444. *
  2445. * 1. An array of string control names, e.g. `['address', 'street']`
  2446. * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
  2447. *
  2448. * @returns error data for that particular error. If the control or error is not present,
  2449. * null is returned.
  2450. */
  2451. getError(errorCode, path) {
  2452. const control = path ? this.get(path) : this;
  2453. return control && control.errors ? control.errors[errorCode] : null;
  2454. }
  2455. /**
  2456. * @description
  2457. * Reports whether the control with the given path has the error specified.
  2458. *
  2459. * @param errorCode The code of the error to check
  2460. * @param path A list of control names that designates how to move from the current control
  2461. * to the control that should be queried for errors.
  2462. *
  2463. * @usageNotes
  2464. * For example, for the following `FormGroup`:
  2465. *
  2466. * ```ts
  2467. * form = new FormGroup({
  2468. * address: new FormGroup({ street: new FormControl() })
  2469. * });
  2470. * ```
  2471. *
  2472. * The path to the 'street' control from the root form would be 'address' -> 'street'.
  2473. *
  2474. * It can be provided to this method in one of two formats:
  2475. *
  2476. * 1. An array of string control names, e.g. `['address', 'street']`
  2477. * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
  2478. *
  2479. * If no path is given, this method checks for the error on the current control.
  2480. *
  2481. * @returns whether the given error is present in the control at the given path.
  2482. *
  2483. * If the control is not present, false is returned.
  2484. */
  2485. hasError(errorCode, path) {
  2486. return !!this.getError(errorCode, path);
  2487. }
  2488. /**
  2489. * Retrieves the top-level ancestor of this control.
  2490. */
  2491. get root() {
  2492. let x = this;
  2493. while (x._parent) {
  2494. x = x._parent;
  2495. }
  2496. return x;
  2497. }
  2498. /** @internal */
  2499. _updateControlsErrors(emitEvent, changedControl, shouldHaveEmitted) {
  2500. this.status = this._calculateStatus();
  2501. if (emitEvent) {
  2502. this.statusChanges.emit(this.status);
  2503. }
  2504. // The Events Observable expose a slight different bevahior than the statusChanges obs
  2505. // An async validator will still emit a StatusChangeEvent is a previously cancelled
  2506. // async validator has emitEvent set to true
  2507. if (emitEvent || shouldHaveEmitted) {
  2508. this._events.next(new StatusChangeEvent(this.status, changedControl));
  2509. }
  2510. if (this._parent) {
  2511. this._parent._updateControlsErrors(emitEvent, changedControl, shouldHaveEmitted);
  2512. }
  2513. }
  2514. /** @internal */
  2515. _initObservables() {
  2516. // TODO: this should be piped from events() but is breaking in G3
  2517. this.valueChanges = new EventEmitter();
  2518. this.statusChanges = new EventEmitter();
  2519. }
  2520. _calculateStatus() {
  2521. if (this._allControlsDisabled())
  2522. return DISABLED;
  2523. if (this.errors)
  2524. return INVALID;
  2525. if (this._hasOwnPendingAsyncValidator || this._anyControlsHaveStatus(PENDING))
  2526. return PENDING;
  2527. if (this._anyControlsHaveStatus(INVALID))
  2528. return INVALID;
  2529. return VALID;
  2530. }
  2531. /** @internal */
  2532. _anyControlsHaveStatus(status) {
  2533. return this._anyControls((control) => control.status === status);
  2534. }
  2535. /** @internal */
  2536. _anyControlsDirty() {
  2537. return this._anyControls((control) => control.dirty);
  2538. }
  2539. /** @internal */
  2540. _anyControlsTouched() {
  2541. return this._anyControls((control) => control.touched);
  2542. }
  2543. /** @internal */
  2544. _updatePristine(opts, changedControl) {
  2545. const newPristine = !this._anyControlsDirty();
  2546. const changed = this.pristine !== newPristine;
  2547. this.pristine = newPristine;
  2548. if (this._parent && !opts.onlySelf) {
  2549. this._parent._updatePristine(opts, changedControl);
  2550. }
  2551. if (changed) {
  2552. this._events.next(new PristineChangeEvent(this.pristine, changedControl));
  2553. }
  2554. }
  2555. /** @internal */
  2556. _updateTouched(opts = {}, changedControl) {
  2557. this.touched = this._anyControlsTouched();
  2558. this._events.next(new TouchedChangeEvent(this.touched, changedControl));
  2559. if (this._parent && !opts.onlySelf) {
  2560. this._parent._updateTouched(opts, changedControl);
  2561. }
  2562. }
  2563. /** @internal */
  2564. _onDisabledChange = [];
  2565. /** @internal */
  2566. _registerOnCollectionChange(fn) {
  2567. this._onCollectionChange = fn;
  2568. }
  2569. /** @internal */
  2570. _setUpdateStrategy(opts) {
  2571. if (isOptionsObj(opts) && opts.updateOn != null) {
  2572. this._updateOn = opts.updateOn;
  2573. }
  2574. }
  2575. /**
  2576. * Check to see if parent has been marked artificially dirty.
  2577. *
  2578. * @internal
  2579. */
  2580. _parentMarkedDirty(onlySelf) {
  2581. const parentDirty = this._parent && this._parent.dirty;
  2582. return !onlySelf && !!parentDirty && !this._parent._anyControlsDirty();
  2583. }
  2584. /** @internal */
  2585. _find(name) {
  2586. return null;
  2587. }
  2588. /**
  2589. * Internal implementation of the `setValidators` method. Needs to be separated out into a
  2590. * different method, because it is called in the constructor and it can break cases where
  2591. * a control is extended.
  2592. */
  2593. _assignValidators(validators) {
  2594. this._rawValidators = Array.isArray(validators) ? validators.slice() : validators;
  2595. this._composedValidatorFn = coerceToValidator(this._rawValidators);
  2596. }
  2597. /**
  2598. * Internal implementation of the `setAsyncValidators` method. Needs to be separated out into a
  2599. * different method, because it is called in the constructor and it can break cases where
  2600. * a control is extended.
  2601. */
  2602. _assignAsyncValidators(validators) {
  2603. this._rawAsyncValidators = Array.isArray(validators) ? validators.slice() : validators;
  2604. this._composedAsyncValidatorFn = coerceToAsyncValidator(this._rawAsyncValidators);
  2605. }
  2606. }
  2607. /**
  2608. * Tracks the value and validity state of a group of `FormControl` instances.
  2609. *
  2610. * A `FormGroup` aggregates the values of each child `FormControl` into one object,
  2611. * with each control name as the key. It calculates its status by reducing the status values
  2612. * of its children. For example, if one of the controls in a group is invalid, the entire
  2613. * group becomes invalid.
  2614. *
  2615. * `FormGroup` is one of the four fundamental building blocks used to define forms in Angular,
  2616. * along with `FormControl`, `FormArray`, and `FormRecord`.
  2617. *
  2618. * When instantiating a `FormGroup`, pass in a collection of child controls as the first
  2619. * argument. The key for each child registers the name for the control.
  2620. *
  2621. * `FormGroup` is intended for use cases where the keys are known ahead of time.
  2622. * If you need to dynamically add and remove controls, use {@link FormRecord} instead.
  2623. *
  2624. * `FormGroup` accepts an optional type parameter `TControl`, which is an object type with inner
  2625. * control types as values.
  2626. *
  2627. * @usageNotes
  2628. *
  2629. * ### Create a form group with 2 controls
  2630. *
  2631. * ```ts
  2632. * const form = new FormGroup({
  2633. * first: new FormControl('Nancy', Validators.minLength(2)),
  2634. * last: new FormControl('Drew'),
  2635. * });
  2636. *
  2637. * console.log(form.value); // {first: 'Nancy', last; 'Drew'}
  2638. * console.log(form.status); // 'VALID'
  2639. * ```
  2640. *
  2641. * ### The type argument, and optional controls
  2642. *
  2643. * `FormGroup` accepts one generic argument, which is an object containing its inner controls.
  2644. * This type will usually be inferred automatically, but you can always specify it explicitly if you
  2645. * wish.
  2646. *
  2647. * If you have controls that are optional (i.e. they can be removed, you can use the `?` in the
  2648. * type):
  2649. *
  2650. * ```ts
  2651. * const form = new FormGroup<{
  2652. * first: FormControl<string|null>,
  2653. * middle?: FormControl<string|null>, // Middle name is optional.
  2654. * last: FormControl<string|null>,
  2655. * }>({
  2656. * first: new FormControl('Nancy'),
  2657. * last: new FormControl('Drew'),
  2658. * });
  2659. * ```
  2660. *
  2661. * ### Create a form group with a group-level validator
  2662. *
  2663. * You include group-level validators as the second arg, or group-level async
  2664. * validators as the third arg. These come in handy when you want to perform validation
  2665. * that considers the value of more than one child control.
  2666. *
  2667. * ```ts
  2668. * const form = new FormGroup({
  2669. * password: new FormControl('', Validators.minLength(2)),
  2670. * passwordConfirm: new FormControl('', Validators.minLength(2)),
  2671. * }, passwordMatchValidator);
  2672. *
  2673. *
  2674. * function passwordMatchValidator(g: FormGroup) {
  2675. * return g.get('password').value === g.get('passwordConfirm').value
  2676. * ? null : {'mismatch': true};
  2677. * }
  2678. * ```
  2679. *
  2680. * Like `FormControl` instances, you choose to pass in
  2681. * validators and async validators as part of an options object.
  2682. *
  2683. * ```ts
  2684. * const form = new FormGroup({
  2685. * password: new FormControl('')
  2686. * passwordConfirm: new FormControl('')
  2687. * }, { validators: passwordMatchValidator, asyncValidators: otherValidator });
  2688. * ```
  2689. *
  2690. * ### Set the updateOn property for all controls in a form group
  2691. *
  2692. * The options object is used to set a default value for each child
  2693. * control's `updateOn` property. If you set `updateOn` to `'blur'` at the
  2694. * group level, all child controls default to 'blur', unless the child
  2695. * has explicitly specified a different `updateOn` value.
  2696. *
  2697. * ```ts
  2698. * const c = new FormGroup({
  2699. * one: new FormControl()
  2700. * }, { updateOn: 'blur' });
  2701. * ```
  2702. *
  2703. * ### Using a FormGroup with optional controls
  2704. *
  2705. * It is possible to have optional controls in a FormGroup. An optional control can be removed later
  2706. * using `removeControl`, and can be omitted when calling `reset`. Optional controls must be
  2707. * declared optional in the group's type.
  2708. *
  2709. * ```ts
  2710. * const c = new FormGroup<{one?: FormControl<string>}>({
  2711. * one: new FormControl('')
  2712. * });
  2713. * ```
  2714. *
  2715. * Notice that `c.value.one` has type `string|null|undefined`. This is because calling `c.reset({})`
  2716. * without providing the optional key `one` will cause it to become `null`.
  2717. *
  2718. * @publicApi
  2719. */
  2720. class FormGroup extends AbstractControl {
  2721. /**
  2722. * Creates a new `FormGroup` instance.
  2723. *
  2724. * @param controls A collection of child controls. The key for each child is the name
  2725. * under which it is registered.
  2726. *
  2727. * @param validatorOrOpts A synchronous validator function, or an array of
  2728. * such functions, or an `AbstractControlOptions` object that contains validation functions
  2729. * and a validation trigger.
  2730. *
  2731. * @param asyncValidator A single async validator or array of async validator functions
  2732. *
  2733. */
  2734. constructor(controls, validatorOrOpts, asyncValidator) {
  2735. super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
  2736. (typeof ngDevMode === 'undefined' || ngDevMode) && validateFormGroupControls(controls);
  2737. this.controls = controls;
  2738. this._initObservables();
  2739. this._setUpdateStrategy(validatorOrOpts);
  2740. this._setUpControls();
  2741. this.updateValueAndValidity({
  2742. onlySelf: true,
  2743. // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
  2744. // `VALID` or `INVALID`. The status should be broadcasted via the `statusChanges` observable,
  2745. // so we set `emitEvent` to `true` to allow that during the control creation process.
  2746. emitEvent: !!this.asyncValidator,
  2747. });
  2748. }
  2749. controls;
  2750. registerControl(name, control) {
  2751. if (this.controls[name])
  2752. return this.controls[name];
  2753. this.controls[name] = control;
  2754. control.setParent(this);
  2755. control._registerOnCollectionChange(this._onCollectionChange);
  2756. return control;
  2757. }
  2758. addControl(name, control, options = {}) {
  2759. this.registerControl(name, control);
  2760. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  2761. this._onCollectionChange();
  2762. }
  2763. /**
  2764. * Remove a control from this group. In a strongly-typed group, required controls cannot be
  2765. * removed.
  2766. *
  2767. * This method also updates the value and validity of the control.
  2768. *
  2769. * @param name The control name to remove from the collection
  2770. * @param options Specifies whether this FormGroup instance should emit events after a
  2771. * control is removed.
  2772. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  2773. * `valueChanges` observables emit events with the latest status and value when the control is
  2774. * removed. When false, no events are emitted.
  2775. */
  2776. removeControl(name, options = {}) {
  2777. if (this.controls[name])
  2778. this.controls[name]._registerOnCollectionChange(() => { });
  2779. delete this.controls[name];
  2780. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  2781. this._onCollectionChange();
  2782. }
  2783. setControl(name, control, options = {}) {
  2784. if (this.controls[name])
  2785. this.controls[name]._registerOnCollectionChange(() => { });
  2786. delete this.controls[name];
  2787. if (control)
  2788. this.registerControl(name, control);
  2789. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  2790. this._onCollectionChange();
  2791. }
  2792. contains(controlName) {
  2793. return this.controls.hasOwnProperty(controlName) && this.controls[controlName].enabled;
  2794. }
  2795. /**
  2796. * Sets the value of the `FormGroup`. It accepts an object that matches
  2797. * the structure of the group, with control names as keys.
  2798. *
  2799. * @usageNotes
  2800. * ### Set the complete value for the form group
  2801. *
  2802. * ```ts
  2803. * const form = new FormGroup({
  2804. * first: new FormControl(),
  2805. * last: new FormControl()
  2806. * });
  2807. *
  2808. * console.log(form.value); // {first: null, last: null}
  2809. *
  2810. * form.setValue({first: 'Nancy', last: 'Drew'});
  2811. * console.log(form.value); // {first: 'Nancy', last: 'Drew'}
  2812. * ```
  2813. *
  2814. * @throws When strict checks fail, such as setting the value of a control
  2815. * that doesn't exist or if you exclude a value of a control that does exist.
  2816. *
  2817. * @param value The new value for the control that matches the structure of the group.
  2818. * @param options Configuration options that determine how the control propagates changes
  2819. * and emits events after the value changes.
  2820. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
  2821. * updateValueAndValidity} method.
  2822. *
  2823. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is
  2824. * false.
  2825. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  2826. * `valueChanges`
  2827. * observables emit events with the latest status and value when the control value is updated.
  2828. * When false, no events are emitted.
  2829. */
  2830. setValue(value, options = {}) {
  2831. assertAllValuesPresent(this, true, value);
  2832. Object.keys(value).forEach((name) => {
  2833. assertControlPresent(this, true, name);
  2834. this.controls[name].setValue(value[name], {
  2835. onlySelf: true,
  2836. emitEvent: options.emitEvent,
  2837. });
  2838. });
  2839. this.updateValueAndValidity(options);
  2840. }
  2841. /**
  2842. * Patches the value of the `FormGroup`. It accepts an object with control
  2843. * names as keys, and does its best to match the values to the correct controls
  2844. * in the group.
  2845. *
  2846. * It accepts both super-sets and sub-sets of the group without throwing an error.
  2847. *
  2848. * @usageNotes
  2849. * ### Patch the value for a form group
  2850. *
  2851. * ```ts
  2852. * const form = new FormGroup({
  2853. * first: new FormControl(),
  2854. * last: new FormControl()
  2855. * });
  2856. * console.log(form.value); // {first: null, last: null}
  2857. *
  2858. * form.patchValue({first: 'Nancy'});
  2859. * console.log(form.value); // {first: 'Nancy', last: null}
  2860. * ```
  2861. *
  2862. * @param value The object that matches the structure of the group.
  2863. * @param options Configuration options that determine how the control propagates changes and
  2864. * emits events after the value is patched.
  2865. * * `onlySelf`: When true, each change only affects this control and not its parent. Default is
  2866. * true.
  2867. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  2868. * `valueChanges` observables emit events with the latest status and value when the control value
  2869. * is updated. When false, no events are emitted. The configuration options are passed to
  2870. * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
  2871. */
  2872. patchValue(value, options = {}) {
  2873. // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
  2874. // `patchValue` can be called recursively and inner data structures might have these values, so
  2875. // we just ignore such cases when a field containing FormGroup instance receives `null` or
  2876. // `undefined` as a value.
  2877. if (value == null /* both `null` and `undefined` */)
  2878. return;
  2879. Object.keys(value).forEach((name) => {
  2880. // The compiler cannot see through the uninstantiated conditional type of `this.controls`, so
  2881. // `as any` is required.
  2882. const control = this.controls[name];
  2883. if (control) {
  2884. control.patchValue(
  2885. /* Guaranteed to be present, due to the outer forEach. */ value[name], { onlySelf: true, emitEvent: options.emitEvent });
  2886. }
  2887. });
  2888. this.updateValueAndValidity(options);
  2889. }
  2890. /**
  2891. * Resets the `FormGroup`, marks all descendants `pristine` and `untouched` and sets
  2892. * the value of all descendants to their default values, or null if no defaults were provided.
  2893. *
  2894. * You reset to a specific form state by passing in a map of states
  2895. * that matches the structure of your form, with control names as keys. The state
  2896. * is a standalone value or a form state object with both a value and a disabled
  2897. * status.
  2898. *
  2899. * @param value Resets the control with an initial value,
  2900. * or an object that defines the initial value and disabled state.
  2901. *
  2902. * @param options Configuration options that determine how the control propagates changes
  2903. * and emits events when the group is reset.
  2904. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is
  2905. * false.
  2906. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  2907. * `valueChanges`
  2908. * observables emit events with the latest status and value when the control is reset.
  2909. * When false, no events are emitted.
  2910. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
  2911. * updateValueAndValidity} method.
  2912. *
  2913. * @usageNotes
  2914. *
  2915. * ### Reset the form group values
  2916. *
  2917. * ```ts
  2918. * const form = new FormGroup({
  2919. * first: new FormControl('first name'),
  2920. * last: new FormControl('last name')
  2921. * });
  2922. *
  2923. * console.log(form.value); // {first: 'first name', last: 'last name'}
  2924. *
  2925. * form.reset({ first: 'name', last: 'last name' });
  2926. *
  2927. * console.log(form.value); // {first: 'name', last: 'last name'}
  2928. * ```
  2929. *
  2930. * ### Reset the form group values and disabled status
  2931. *
  2932. * ```ts
  2933. * const form = new FormGroup({
  2934. * first: new FormControl('first name'),
  2935. * last: new FormControl('last name')
  2936. * });
  2937. *
  2938. * form.reset({
  2939. * first: {value: 'name', disabled: true},
  2940. * last: 'last'
  2941. * });
  2942. *
  2943. * console.log(form.value); // {last: 'last'}
  2944. * console.log(form.get('first').status); // 'DISABLED'
  2945. * ```
  2946. */
  2947. reset(value = {}, options = {}) {
  2948. this._forEachChild((control, name) => {
  2949. control.reset(value ? value[name] : null, {
  2950. onlySelf: true,
  2951. emitEvent: options.emitEvent,
  2952. });
  2953. });
  2954. this._updatePristine(options, this);
  2955. this._updateTouched(options, this);
  2956. this.updateValueAndValidity(options);
  2957. }
  2958. /**
  2959. * The aggregate value of the `FormGroup`, including any disabled controls.
  2960. *
  2961. * Retrieves all values regardless of disabled status.
  2962. */
  2963. getRawValue() {
  2964. return this._reduceChildren({}, (acc, control, name) => {
  2965. acc[name] = control.getRawValue();
  2966. return acc;
  2967. });
  2968. }
  2969. /** @internal */
  2970. _syncPendingControls() {
  2971. let subtreeUpdated = this._reduceChildren(false, (updated, child) => {
  2972. return child._syncPendingControls() ? true : updated;
  2973. });
  2974. if (subtreeUpdated)
  2975. this.updateValueAndValidity({ onlySelf: true });
  2976. return subtreeUpdated;
  2977. }
  2978. /** @internal */
  2979. _forEachChild(cb) {
  2980. Object.keys(this.controls).forEach((key) => {
  2981. // The list of controls can change (for ex. controls might be removed) while the loop
  2982. // is running (as a result of invoking Forms API in `valueChanges` subscription), so we
  2983. // have to null check before invoking the callback.
  2984. const control = this.controls[key];
  2985. control && cb(control, key);
  2986. });
  2987. }
  2988. /** @internal */
  2989. _setUpControls() {
  2990. this._forEachChild((control) => {
  2991. control.setParent(this);
  2992. control._registerOnCollectionChange(this._onCollectionChange);
  2993. });
  2994. }
  2995. /** @internal */
  2996. _updateValue() {
  2997. this.value = this._reduceValue();
  2998. }
  2999. /** @internal */
  3000. _anyControls(condition) {
  3001. for (const [controlName, control] of Object.entries(this.controls)) {
  3002. if (this.contains(controlName) && condition(control)) {
  3003. return true;
  3004. }
  3005. }
  3006. return false;
  3007. }
  3008. /** @internal */
  3009. _reduceValue() {
  3010. let acc = {};
  3011. return this._reduceChildren(acc, (acc, control, name) => {
  3012. if (control.enabled || this.disabled) {
  3013. acc[name] = control.value;
  3014. }
  3015. return acc;
  3016. });
  3017. }
  3018. /** @internal */
  3019. _reduceChildren(initValue, fn) {
  3020. let res = initValue;
  3021. this._forEachChild((control, name) => {
  3022. res = fn(res, control, name);
  3023. });
  3024. return res;
  3025. }
  3026. /** @internal */
  3027. _allControlsDisabled() {
  3028. for (const controlName of Object.keys(this.controls)) {
  3029. if (this.controls[controlName].enabled) {
  3030. return false;
  3031. }
  3032. }
  3033. return Object.keys(this.controls).length > 0 || this.disabled;
  3034. }
  3035. /** @internal */
  3036. _find(name) {
  3037. return this.controls.hasOwnProperty(name)
  3038. ? this.controls[name]
  3039. : null;
  3040. }
  3041. }
  3042. /**
  3043. * Will validate that none of the controls has a key with a dot
  3044. * Throws other wise
  3045. */
  3046. function validateFormGroupControls(controls) {
  3047. const invalidKeys = Object.keys(controls).filter((key) => key.includes('.'));
  3048. if (invalidKeys.length > 0) {
  3049. // TODO: make this an error once there are no more uses in G3
  3050. console.warn(`FormGroup keys cannot include \`.\`, please replace the keys for: ${invalidKeys.join(',')}.`);
  3051. }
  3052. }
  3053. const UntypedFormGroup = FormGroup;
  3054. /**
  3055. * @description
  3056. * Asserts that the given control is an instance of `FormGroup`
  3057. *
  3058. * @publicApi
  3059. */
  3060. const isFormGroup = (control) => control instanceof FormGroup;
  3061. /**
  3062. * Tracks the value and validity state of a collection of `FormControl` instances, each of which has
  3063. * the same value type.
  3064. *
  3065. * `FormRecord` is very similar to {@link FormGroup}, except it can be used with a dynamic keys,
  3066. * with controls added and removed as needed.
  3067. *
  3068. * `FormRecord` accepts one generic argument, which describes the type of the controls it contains.
  3069. *
  3070. * @usageNotes
  3071. *
  3072. * ```ts
  3073. * let numbers = new FormRecord({bill: new FormControl('415-123-456')});
  3074. * numbers.addControl('bob', new FormControl('415-234-567'));
  3075. * numbers.removeControl('bill');
  3076. * ```
  3077. *
  3078. * @publicApi
  3079. */
  3080. class FormRecord extends FormGroup {
  3081. }
  3082. /**
  3083. * @description
  3084. * Asserts that the given control is an instance of `FormRecord`
  3085. *
  3086. * @publicApi
  3087. */
  3088. const isFormRecord = (control) => control instanceof FormRecord;
  3089. /**
  3090. * Token to provide to allow SetDisabledState to always be called when a CVA is added, regardless of
  3091. * whether the control is disabled or enabled.
  3092. *
  3093. * @see {@link FormsModule#withconfig}
  3094. */
  3095. const CALL_SET_DISABLED_STATE = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'CallSetDisabledState' : '', {
  3096. providedIn: 'root',
  3097. factory: () => setDisabledStateDefault,
  3098. });
  3099. /**
  3100. * Whether to use the fixed setDisabledState behavior by default.
  3101. */
  3102. const setDisabledStateDefault = 'always';
  3103. function controlPath(name, parent) {
  3104. return [...parent.path, name];
  3105. }
  3106. /**
  3107. * Links a Form control and a Form directive by setting up callbacks (such as `onChange`) on both
  3108. * instances. This function is typically invoked when form directive is being initialized.
  3109. *
  3110. * @param control Form control instance that should be linked.
  3111. * @param dir Directive that should be linked with a given control.
  3112. */
  3113. function setUpControl(control, dir, callSetDisabledState = setDisabledStateDefault) {
  3114. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  3115. if (!control)
  3116. _throwError(dir, 'Cannot find control with');
  3117. if (!dir.valueAccessor)
  3118. _throwMissingValueAccessorError(dir);
  3119. }
  3120. setUpValidators(control, dir);
  3121. dir.valueAccessor.writeValue(control.value);
  3122. // The legacy behavior only calls the CVA's `setDisabledState` if the control is disabled.
  3123. // If the `callSetDisabledState` option is set to `always`, then this bug is fixed and
  3124. // the method is always called.
  3125. if (control.disabled || callSetDisabledState === 'always') {
  3126. dir.valueAccessor.setDisabledState?.(control.disabled);
  3127. }
  3128. setUpViewChangePipeline(control, dir);
  3129. setUpModelChangePipeline(control, dir);
  3130. setUpBlurPipeline(control, dir);
  3131. setUpDisabledChangeHandler(control, dir);
  3132. }
  3133. /**
  3134. * Reverts configuration performed by the `setUpControl` control function.
  3135. * Effectively disconnects form control with a given form directive.
  3136. * This function is typically invoked when corresponding form directive is being destroyed.
  3137. *
  3138. * @param control Form control which should be cleaned up.
  3139. * @param dir Directive that should be disconnected from a given control.
  3140. * @param validateControlPresenceOnChange Flag that indicates whether onChange handler should
  3141. * contain asserts to verify that it's not called once directive is destroyed. We need this flag
  3142. * to avoid potentially breaking changes caused by better control cleanup introduced in #39235.
  3143. */
  3144. function cleanUpControl(control, dir, validateControlPresenceOnChange = true) {
  3145. const noop = () => {
  3146. if (validateControlPresenceOnChange && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  3147. _noControlError(dir);
  3148. }
  3149. };
  3150. // The `valueAccessor` field is typically defined on FromControl and FormControlName directive
  3151. // instances and there is a logic in `selectValueAccessor` function that throws if it's not the
  3152. // case. We still check the presence of `valueAccessor` before invoking its methods to make sure
  3153. // that cleanup works correctly if app code or tests are setup to ignore the error thrown from
  3154. // `selectValueAccessor`. See https://github.com/angular/angular/issues/40521.
  3155. if (dir.valueAccessor) {
  3156. dir.valueAccessor.registerOnChange(noop);
  3157. dir.valueAccessor.registerOnTouched(noop);
  3158. }
  3159. cleanUpValidators(control, dir);
  3160. if (control) {
  3161. dir._invokeOnDestroyCallbacks();
  3162. control._registerOnCollectionChange(() => { });
  3163. }
  3164. }
  3165. function registerOnValidatorChange(validators, onChange) {
  3166. validators.forEach((validator) => {
  3167. if (validator.registerOnValidatorChange)
  3168. validator.registerOnValidatorChange(onChange);
  3169. });
  3170. }
  3171. /**
  3172. * Sets up disabled change handler function on a given form control if ControlValueAccessor
  3173. * associated with a given directive instance supports the `setDisabledState` call.
  3174. *
  3175. * @param control Form control where disabled change handler should be setup.
  3176. * @param dir Corresponding directive instance associated with this control.
  3177. */
  3178. function setUpDisabledChangeHandler(control, dir) {
  3179. if (dir.valueAccessor.setDisabledState) {
  3180. const onDisabledChange = (isDisabled) => {
  3181. dir.valueAccessor.setDisabledState(isDisabled);
  3182. };
  3183. control.registerOnDisabledChange(onDisabledChange);
  3184. // Register a callback function to cleanup disabled change handler
  3185. // from a control instance when a directive is destroyed.
  3186. dir._registerOnDestroy(() => {
  3187. control._unregisterOnDisabledChange(onDisabledChange);
  3188. });
  3189. }
  3190. }
  3191. /**
  3192. * Sets up sync and async directive validators on provided form control.
  3193. * This function merges validators from the directive into the validators of the control.
  3194. *
  3195. * @param control Form control where directive validators should be setup.
  3196. * @param dir Directive instance that contains validators to be setup.
  3197. */
  3198. function setUpValidators(control, dir) {
  3199. const validators = getControlValidators(control);
  3200. if (dir.validator !== null) {
  3201. control.setValidators(mergeValidators(validators, dir.validator));
  3202. }
  3203. else if (typeof validators === 'function') {
  3204. // If sync validators are represented by a single validator function, we force the
  3205. // `Validators.compose` call to happen by executing the `setValidators` function with
  3206. // an array that contains that function. We need this to avoid possible discrepancies in
  3207. // validators behavior, so sync validators are always processed by the `Validators.compose`.
  3208. // Note: we should consider moving this logic inside the `setValidators` function itself, so we
  3209. // have consistent behavior on AbstractControl API level. The same applies to the async
  3210. // validators logic below.
  3211. control.setValidators([validators]);
  3212. }
  3213. const asyncValidators = getControlAsyncValidators(control);
  3214. if (dir.asyncValidator !== null) {
  3215. control.setAsyncValidators(mergeValidators(asyncValidators, dir.asyncValidator));
  3216. }
  3217. else if (typeof asyncValidators === 'function') {
  3218. control.setAsyncValidators([asyncValidators]);
  3219. }
  3220. // Re-run validation when validator binding changes, e.g. minlength=3 -> minlength=4
  3221. const onValidatorChange = () => control.updateValueAndValidity();
  3222. registerOnValidatorChange(dir._rawValidators, onValidatorChange);
  3223. registerOnValidatorChange(dir._rawAsyncValidators, onValidatorChange);
  3224. }
  3225. /**
  3226. * Cleans up sync and async directive validators on provided form control.
  3227. * This function reverts the setup performed by the `setUpValidators` function, i.e.
  3228. * removes directive-specific validators from a given control instance.
  3229. *
  3230. * @param control Form control from where directive validators should be removed.
  3231. * @param dir Directive instance that contains validators to be removed.
  3232. * @returns true if a control was updated as a result of this action.
  3233. */
  3234. function cleanUpValidators(control, dir) {
  3235. let isControlUpdated = false;
  3236. if (control !== null) {
  3237. if (dir.validator !== null) {
  3238. const validators = getControlValidators(control);
  3239. if (Array.isArray(validators) && validators.length > 0) {
  3240. // Filter out directive validator function.
  3241. const updatedValidators = validators.filter((validator) => validator !== dir.validator);
  3242. if (updatedValidators.length !== validators.length) {
  3243. isControlUpdated = true;
  3244. control.setValidators(updatedValidators);
  3245. }
  3246. }
  3247. }
  3248. if (dir.asyncValidator !== null) {
  3249. const asyncValidators = getControlAsyncValidators(control);
  3250. if (Array.isArray(asyncValidators) && asyncValidators.length > 0) {
  3251. // Filter out directive async validator function.
  3252. const updatedAsyncValidators = asyncValidators.filter((asyncValidator) => asyncValidator !== dir.asyncValidator);
  3253. if (updatedAsyncValidators.length !== asyncValidators.length) {
  3254. isControlUpdated = true;
  3255. control.setAsyncValidators(updatedAsyncValidators);
  3256. }
  3257. }
  3258. }
  3259. }
  3260. // Clear onValidatorChange callbacks by providing a noop function.
  3261. const noop = () => { };
  3262. registerOnValidatorChange(dir._rawValidators, noop);
  3263. registerOnValidatorChange(dir._rawAsyncValidators, noop);
  3264. return isControlUpdated;
  3265. }
  3266. function setUpViewChangePipeline(control, dir) {
  3267. dir.valueAccessor.registerOnChange((newValue) => {
  3268. control._pendingValue = newValue;
  3269. control._pendingChange = true;
  3270. control._pendingDirty = true;
  3271. if (control.updateOn === 'change')
  3272. updateControl(control, dir);
  3273. });
  3274. }
  3275. function setUpBlurPipeline(control, dir) {
  3276. dir.valueAccessor.registerOnTouched(() => {
  3277. control._pendingTouched = true;
  3278. if (control.updateOn === 'blur' && control._pendingChange)
  3279. updateControl(control, dir);
  3280. if (control.updateOn !== 'submit')
  3281. control.markAsTouched();
  3282. });
  3283. }
  3284. function updateControl(control, dir) {
  3285. if (control._pendingDirty)
  3286. control.markAsDirty();
  3287. control.setValue(control._pendingValue, { emitModelToViewChange: false });
  3288. dir.viewToModelUpdate(control._pendingValue);
  3289. control._pendingChange = false;
  3290. }
  3291. function setUpModelChangePipeline(control, dir) {
  3292. const onChange = (newValue, emitModelEvent) => {
  3293. // control -> view
  3294. dir.valueAccessor.writeValue(newValue);
  3295. // control -> ngModel
  3296. if (emitModelEvent)
  3297. dir.viewToModelUpdate(newValue);
  3298. };
  3299. control.registerOnChange(onChange);
  3300. // Register a callback function to cleanup onChange handler
  3301. // from a control instance when a directive is destroyed.
  3302. dir._registerOnDestroy(() => {
  3303. control._unregisterOnChange(onChange);
  3304. });
  3305. }
  3306. /**
  3307. * Links a FormGroup or FormArray instance and corresponding Form directive by setting up validators
  3308. * present in the view.
  3309. *
  3310. * @param control FormGroup or FormArray instance that should be linked.
  3311. * @param dir Directive that provides view validators.
  3312. */
  3313. function setUpFormContainer(control, dir) {
  3314. if (control == null && (typeof ngDevMode === 'undefined' || ngDevMode))
  3315. _throwError(dir, 'Cannot find control with');
  3316. setUpValidators(control, dir);
  3317. }
  3318. /**
  3319. * Reverts the setup performed by the `setUpFormContainer` function.
  3320. *
  3321. * @param control FormGroup or FormArray instance that should be cleaned up.
  3322. * @param dir Directive that provided view validators.
  3323. * @returns true if a control was updated as a result of this action.
  3324. */
  3325. function cleanUpFormContainer(control, dir) {
  3326. return cleanUpValidators(control, dir);
  3327. }
  3328. function _noControlError(dir) {
  3329. return _throwError(dir, 'There is no FormControl instance attached to form control element with');
  3330. }
  3331. function _throwError(dir, message) {
  3332. const messageEnd = _describeControlLocation(dir);
  3333. throw new Error(`${message} ${messageEnd}`);
  3334. }
  3335. function _describeControlLocation(dir) {
  3336. const path = dir.path;
  3337. if (path && path.length > 1)
  3338. return `path: '${path.join(' -> ')}'`;
  3339. if (path?.[0])
  3340. return `name: '${path}'`;
  3341. return 'unspecified name attribute';
  3342. }
  3343. function _throwMissingValueAccessorError(dir) {
  3344. const loc = _describeControlLocation(dir);
  3345. throw new _RuntimeError(-1203 /* RuntimeErrorCode.NG_MISSING_VALUE_ACCESSOR */, `No value accessor for form control ${loc}.`);
  3346. }
  3347. function _throwInvalidValueAccessorError(dir) {
  3348. const loc = _describeControlLocation(dir);
  3349. throw new _RuntimeError(1200 /* RuntimeErrorCode.NG_VALUE_ACCESSOR_NOT_PROVIDED */, `Value accessor was not provided as an array for form control with ${loc}. ` +
  3350. `Check that the \`NG_VALUE_ACCESSOR\` token is configured as a \`multi: true\` provider.`);
  3351. }
  3352. function isPropertyUpdated(changes, viewModel) {
  3353. if (!changes.hasOwnProperty('model'))
  3354. return false;
  3355. const change = changes['model'];
  3356. if (change.isFirstChange())
  3357. return true;
  3358. return !Object.is(viewModel, change.currentValue);
  3359. }
  3360. function isBuiltInAccessor(valueAccessor) {
  3361. // Check if a given value accessor is an instance of a class that directly extends
  3362. // `BuiltInControlValueAccessor` one.
  3363. return Object.getPrototypeOf(valueAccessor.constructor) === BuiltInControlValueAccessor;
  3364. }
  3365. function syncPendingControls(form, directives) {
  3366. form._syncPendingControls();
  3367. directives.forEach((dir) => {
  3368. const control = dir.control;
  3369. if (control.updateOn === 'submit' && control._pendingChange) {
  3370. dir.viewToModelUpdate(control._pendingValue);
  3371. control._pendingChange = false;
  3372. }
  3373. });
  3374. }
  3375. // TODO: vsavkin remove it once https://github.com/angular/angular/issues/3011 is implemented
  3376. function selectValueAccessor(dir, valueAccessors) {
  3377. if (!valueAccessors)
  3378. return null;
  3379. if (!Array.isArray(valueAccessors) && (typeof ngDevMode === 'undefined' || ngDevMode))
  3380. _throwInvalidValueAccessorError(dir);
  3381. let defaultAccessor = undefined;
  3382. let builtinAccessor = undefined;
  3383. let customAccessor = undefined;
  3384. valueAccessors.forEach((v) => {
  3385. if (v.constructor === DefaultValueAccessor) {
  3386. defaultAccessor = v;
  3387. }
  3388. else if (isBuiltInAccessor(v)) {
  3389. if (builtinAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
  3390. _throwError(dir, 'More than one built-in value accessor matches form control with');
  3391. builtinAccessor = v;
  3392. }
  3393. else {
  3394. if (customAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
  3395. _throwError(dir, 'More than one custom value accessor matches form control with');
  3396. customAccessor = v;
  3397. }
  3398. });
  3399. if (customAccessor)
  3400. return customAccessor;
  3401. if (builtinAccessor)
  3402. return builtinAccessor;
  3403. if (defaultAccessor)
  3404. return defaultAccessor;
  3405. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  3406. _throwError(dir, 'No valid value accessor for form control with');
  3407. }
  3408. return null;
  3409. }
  3410. function removeListItem$1(list, el) {
  3411. const index = list.indexOf(el);
  3412. if (index > -1)
  3413. list.splice(index, 1);
  3414. }
  3415. // TODO(kara): remove after deprecation period
  3416. function _ngModelWarning(name, type, instance, warningConfig) {
  3417. if (warningConfig === 'never')
  3418. return;
  3419. if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) ||
  3420. (warningConfig === 'always' && !instance._ngModelWarningSent)) {
  3421. console.warn(ngModelWarning(name));
  3422. type._ngModelWarningSentOnce = true;
  3423. instance._ngModelWarningSent = true;
  3424. }
  3425. }
  3426. const formDirectiveProvider$1 = {
  3427. provide: ControlContainer,
  3428. useExisting: forwardRef(() => NgForm),
  3429. };
  3430. const resolvedPromise$1 = (() => Promise.resolve())();
  3431. /**
  3432. * @description
  3433. * Creates a top-level `FormGroup` instance and binds it to a form
  3434. * to track aggregate form value and validation status.
  3435. *
  3436. * As soon as you import the `FormsModule`, this directive becomes active by default on
  3437. * all `<form>` tags. You don't need to add a special selector.
  3438. *
  3439. * You optionally export the directive into a local template variable using `ngForm` as the key
  3440. * (ex: `#myForm="ngForm"`). This is optional, but useful. Many properties from the underlying
  3441. * `FormGroup` instance are duplicated on the directive itself, so a reference to it
  3442. * gives you access to the aggregate value and validity status of the form, as well as
  3443. * user interaction properties like `dirty` and `touched`.
  3444. *
  3445. * To register child controls with the form, use `NgModel` with a `name`
  3446. * attribute. You may use `NgModelGroup` to create sub-groups within the form.
  3447. *
  3448. * If necessary, listen to the directive's `ngSubmit` event to be notified when the user has
  3449. * triggered a form submission. The `ngSubmit` event emits the original form
  3450. * submission event.
  3451. *
  3452. * In template driven forms, all `<form>` tags are automatically tagged as `NgForm`.
  3453. * To import the `FormsModule` but skip its usage in some forms,
  3454. * for example, to use native HTML5 validation, add the `ngNoForm` and the `<form>`
  3455. * tags won't create an `NgForm` directive. In reactive forms, using `ngNoForm` is
  3456. * unnecessary because the `<form>` tags are inert. In that case, you would
  3457. * refrain from using the `formGroup` directive.
  3458. *
  3459. * @usageNotes
  3460. *
  3461. * ### Listening for form submission
  3462. *
  3463. * The following example shows how to capture the form values from the "ngSubmit" event.
  3464. *
  3465. * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
  3466. *
  3467. * ### Setting the update options
  3468. *
  3469. * The following example shows you how to change the "updateOn" option from its default using
  3470. * ngFormOptions.
  3471. *
  3472. * ```html
  3473. * <form [ngFormOptions]="{updateOn: 'blur'}">
  3474. * <input name="one" ngModel> <!-- this ngModel will update on blur -->
  3475. * </form>
  3476. * ```
  3477. *
  3478. * ### Native DOM validation UI
  3479. *
  3480. * In order to prevent the native DOM form validation UI from interfering with Angular's form
  3481. * validation, Angular automatically adds the `novalidate` attribute on any `<form>` whenever
  3482. * `FormModule` or `ReactiveFormModule` are imported into the application.
  3483. * If you want to explicitly enable native DOM validation UI with Angular forms, you can add the
  3484. * `ngNativeValidate` attribute to the `<form>` element:
  3485. *
  3486. * ```html
  3487. * <form ngNativeValidate>
  3488. * ...
  3489. * </form>
  3490. * ```
  3491. *
  3492. * @ngModule FormsModule
  3493. * @publicApi
  3494. */
  3495. class NgForm extends ControlContainer {
  3496. callSetDisabledState;
  3497. /**
  3498. * @description
  3499. * Returns whether the form submission has been triggered.
  3500. */
  3501. get submitted() {
  3502. return untracked(this.submittedReactive);
  3503. }
  3504. /** @internal */
  3505. _submitted = computed(() => this.submittedReactive());
  3506. submittedReactive = signal(false);
  3507. _directives = new Set();
  3508. /**
  3509. * @description
  3510. * The `FormGroup` instance created for this form.
  3511. */
  3512. form;
  3513. /**
  3514. * @description
  3515. * Event emitter for the "ngSubmit" event
  3516. */
  3517. ngSubmit = new EventEmitter();
  3518. /**
  3519. * @description
  3520. * Tracks options for the `NgForm` instance.
  3521. *
  3522. * **updateOn**: Sets the default `updateOn` value for all child `NgModels` below it
  3523. * unless explicitly set by a child `NgModel` using `ngModelOptions`). Defaults to 'change'.
  3524. * Possible values: `'change'` | `'blur'` | `'submit'`.
  3525. *
  3526. */
  3527. // TODO(issue/24571): remove '!'.
  3528. options;
  3529. constructor(validators, asyncValidators, callSetDisabledState) {
  3530. super();
  3531. this.callSetDisabledState = callSetDisabledState;
  3532. this.form = new FormGroup({}, composeValidators(validators), composeAsyncValidators(asyncValidators));
  3533. }
  3534. /** @nodoc */
  3535. ngAfterViewInit() {
  3536. this._setUpdateStrategy();
  3537. }
  3538. /**
  3539. * @description
  3540. * The directive instance.
  3541. */
  3542. get formDirective() {
  3543. return this;
  3544. }
  3545. /**
  3546. * @description
  3547. * The internal `FormGroup` instance.
  3548. */
  3549. get control() {
  3550. return this.form;
  3551. }
  3552. /**
  3553. * @description
  3554. * Returns an array representing the path to this group. Because this directive
  3555. * always lives at the top level of a form, it is always an empty array.
  3556. */
  3557. get path() {
  3558. return [];
  3559. }
  3560. /**
  3561. * @description
  3562. * Returns a map of the controls in this group.
  3563. */
  3564. get controls() {
  3565. return this.form.controls;
  3566. }
  3567. /**
  3568. * @description
  3569. * Method that sets up the control directive in this group, re-calculates its value
  3570. * and validity, and adds the instance to the internal list of directives.
  3571. *
  3572. * @param dir The `NgModel` directive instance.
  3573. */
  3574. addControl(dir) {
  3575. resolvedPromise$1.then(() => {
  3576. const container = this._findContainer(dir.path);
  3577. dir.control = (container.registerControl(dir.name, dir.control));
  3578. setUpControl(dir.control, dir, this.callSetDisabledState);
  3579. dir.control.updateValueAndValidity({ emitEvent: false });
  3580. this._directives.add(dir);
  3581. });
  3582. }
  3583. /**
  3584. * @description
  3585. * Retrieves the `FormControl` instance from the provided `NgModel` directive.
  3586. *
  3587. * @param dir The `NgModel` directive instance.
  3588. */
  3589. getControl(dir) {
  3590. return this.form.get(dir.path);
  3591. }
  3592. /**
  3593. * @description
  3594. * Removes the `NgModel` instance from the internal list of directives
  3595. *
  3596. * @param dir The `NgModel` directive instance.
  3597. */
  3598. removeControl(dir) {
  3599. resolvedPromise$1.then(() => {
  3600. const container = this._findContainer(dir.path);
  3601. if (container) {
  3602. container.removeControl(dir.name);
  3603. }
  3604. this._directives.delete(dir);
  3605. });
  3606. }
  3607. /**
  3608. * @description
  3609. * Adds a new `NgModelGroup` directive instance to the form.
  3610. *
  3611. * @param dir The `NgModelGroup` directive instance.
  3612. */
  3613. addFormGroup(dir) {
  3614. resolvedPromise$1.then(() => {
  3615. const container = this._findContainer(dir.path);
  3616. const group = new FormGroup({});
  3617. setUpFormContainer(group, dir);
  3618. container.registerControl(dir.name, group);
  3619. group.updateValueAndValidity({ emitEvent: false });
  3620. });
  3621. }
  3622. /**
  3623. * @description
  3624. * Removes the `NgModelGroup` directive instance from the form.
  3625. *
  3626. * @param dir The `NgModelGroup` directive instance.
  3627. */
  3628. removeFormGroup(dir) {
  3629. resolvedPromise$1.then(() => {
  3630. const container = this._findContainer(dir.path);
  3631. if (container) {
  3632. container.removeControl(dir.name);
  3633. }
  3634. });
  3635. }
  3636. /**
  3637. * @description
  3638. * Retrieves the `FormGroup` for a provided `NgModelGroup` directive instance
  3639. *
  3640. * @param dir The `NgModelGroup` directive instance.
  3641. */
  3642. getFormGroup(dir) {
  3643. return this.form.get(dir.path);
  3644. }
  3645. /**
  3646. * Sets the new value for the provided `NgControl` directive.
  3647. *
  3648. * @param dir The `NgControl` directive instance.
  3649. * @param value The new value for the directive's control.
  3650. */
  3651. updateModel(dir, value) {
  3652. resolvedPromise$1.then(() => {
  3653. const ctrl = this.form.get(dir.path);
  3654. ctrl.setValue(value);
  3655. });
  3656. }
  3657. /**
  3658. * @description
  3659. * Sets the value for this `FormGroup`.
  3660. *
  3661. * @param value The new value
  3662. */
  3663. setValue(value) {
  3664. this.control.setValue(value);
  3665. }
  3666. /**
  3667. * @description
  3668. * Method called when the "submit" event is triggered on the form.
  3669. * Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
  3670. *
  3671. * @param $event The "submit" event object
  3672. */
  3673. onSubmit($event) {
  3674. this.submittedReactive.set(true);
  3675. syncPendingControls(this.form, this._directives);
  3676. this.ngSubmit.emit($event);
  3677. // Forms with `method="dialog"` have some special behavior
  3678. // that won't reload the page and that shouldn't be prevented.
  3679. return $event?.target?.method === 'dialog';
  3680. }
  3681. /**
  3682. * @description
  3683. * Method called when the "reset" event is triggered on the form.
  3684. */
  3685. onReset() {
  3686. this.resetForm();
  3687. }
  3688. /**
  3689. * @description
  3690. * Resets the form to an initial value and resets its submitted status.
  3691. *
  3692. * @param value The new value for the form.
  3693. */
  3694. resetForm(value = undefined) {
  3695. this.form.reset(value);
  3696. this.submittedReactive.set(false);
  3697. }
  3698. _setUpdateStrategy() {
  3699. if (this.options && this.options.updateOn != null) {
  3700. this.form._updateOn = this.options.updateOn;
  3701. }
  3702. }
  3703. _findContainer(path) {
  3704. path.pop();
  3705. return path.length ? this.form.get(path) : this.form;
  3706. }
  3707. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgForm, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  3708. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgForm, isStandalone: false, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: { options: ["ngFormOptions", "options"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider$1], exportAs: ["ngForm"], usesInheritance: true, ngImport: i0 });
  3709. }
  3710. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgForm, decorators: [{
  3711. type: Directive,
  3712. args: [{
  3713. selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]',
  3714. providers: [formDirectiveProvider$1],
  3715. host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
  3716. outputs: ['ngSubmit'],
  3717. exportAs: 'ngForm',
  3718. standalone: false,
  3719. }]
  3720. }], ctorParameters: () => [{ type: undefined, decorators: [{
  3721. type: Optional
  3722. }, {
  3723. type: Self
  3724. }, {
  3725. type: Inject,
  3726. args: [NG_VALIDATORS]
  3727. }] }, { type: undefined, decorators: [{
  3728. type: Optional
  3729. }, {
  3730. type: Self
  3731. }, {
  3732. type: Inject,
  3733. args: [NG_ASYNC_VALIDATORS]
  3734. }] }, { type: undefined, decorators: [{
  3735. type: Optional
  3736. }, {
  3737. type: Inject,
  3738. args: [CALL_SET_DISABLED_STATE]
  3739. }] }], propDecorators: { options: [{
  3740. type: Input,
  3741. args: ['ngFormOptions']
  3742. }] } });
  3743. function removeListItem(list, el) {
  3744. const index = list.indexOf(el);
  3745. if (index > -1)
  3746. list.splice(index, 1);
  3747. }
  3748. function isFormControlState(formState) {
  3749. return (typeof formState === 'object' &&
  3750. formState !== null &&
  3751. Object.keys(formState).length === 2 &&
  3752. 'value' in formState &&
  3753. 'disabled' in formState);
  3754. }
  3755. const FormControl = class FormControl extends AbstractControl {
  3756. /** @publicApi */
  3757. defaultValue = null;
  3758. /** @internal */
  3759. _onChange = [];
  3760. /** @internal */
  3761. _pendingValue;
  3762. /** @internal */
  3763. _pendingChange = false;
  3764. constructor(
  3765. // formState and defaultValue will only be null if T is nullable
  3766. formState = null, validatorOrOpts, asyncValidator) {
  3767. super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
  3768. this._applyFormState(formState);
  3769. this._setUpdateStrategy(validatorOrOpts);
  3770. this._initObservables();
  3771. this.updateValueAndValidity({
  3772. onlySelf: true,
  3773. // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
  3774. // `VALID` or `INVALID`.
  3775. // The status should be broadcasted via the `statusChanges` observable, so we set
  3776. // `emitEvent` to `true` to allow that during the control creation process.
  3777. emitEvent: !!this.asyncValidator,
  3778. });
  3779. if (isOptionsObj(validatorOrOpts) &&
  3780. (validatorOrOpts.nonNullable || validatorOrOpts.initialValueIsDefault)) {
  3781. if (isFormControlState(formState)) {
  3782. this.defaultValue = formState.value;
  3783. }
  3784. else {
  3785. this.defaultValue = formState;
  3786. }
  3787. }
  3788. }
  3789. setValue(value, options = {}) {
  3790. this.value = this._pendingValue = value;
  3791. if (this._onChange.length && options.emitModelToViewChange !== false) {
  3792. this._onChange.forEach((changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
  3793. }
  3794. this.updateValueAndValidity(options);
  3795. }
  3796. patchValue(value, options = {}) {
  3797. this.setValue(value, options);
  3798. }
  3799. reset(formState = this.defaultValue, options = {}) {
  3800. this._applyFormState(formState);
  3801. this.markAsPristine(options);
  3802. this.markAsUntouched(options);
  3803. this.setValue(this.value, options);
  3804. this._pendingChange = false;
  3805. }
  3806. /** @internal */
  3807. _updateValue() { }
  3808. /** @internal */
  3809. _anyControls(condition) {
  3810. return false;
  3811. }
  3812. /** @internal */
  3813. _allControlsDisabled() {
  3814. return this.disabled;
  3815. }
  3816. registerOnChange(fn) {
  3817. this._onChange.push(fn);
  3818. }
  3819. /** @internal */
  3820. _unregisterOnChange(fn) {
  3821. removeListItem(this._onChange, fn);
  3822. }
  3823. registerOnDisabledChange(fn) {
  3824. this._onDisabledChange.push(fn);
  3825. }
  3826. /** @internal */
  3827. _unregisterOnDisabledChange(fn) {
  3828. removeListItem(this._onDisabledChange, fn);
  3829. }
  3830. /** @internal */
  3831. _forEachChild(cb) { }
  3832. /** @internal */
  3833. _syncPendingControls() {
  3834. if (this.updateOn === 'submit') {
  3835. if (this._pendingDirty)
  3836. this.markAsDirty();
  3837. if (this._pendingTouched)
  3838. this.markAsTouched();
  3839. if (this._pendingChange) {
  3840. this.setValue(this._pendingValue, { onlySelf: true, emitModelToViewChange: false });
  3841. return true;
  3842. }
  3843. }
  3844. return false;
  3845. }
  3846. _applyFormState(formState) {
  3847. if (isFormControlState(formState)) {
  3848. this.value = this._pendingValue = formState.value;
  3849. formState.disabled
  3850. ? this.disable({ onlySelf: true, emitEvent: false })
  3851. : this.enable({ onlySelf: true, emitEvent: false });
  3852. }
  3853. else {
  3854. this.value = this._pendingValue = formState;
  3855. }
  3856. }
  3857. };
  3858. const UntypedFormControl = FormControl;
  3859. /**
  3860. * @description
  3861. * Asserts that the given control is an instance of `FormControl`
  3862. *
  3863. * @publicApi
  3864. */
  3865. const isFormControl = (control) => control instanceof FormControl;
  3866. /**
  3867. * @description
  3868. * A base class for code shared between the `NgModelGroup` and `FormGroupName` directives.
  3869. *
  3870. * @publicApi
  3871. */
  3872. class AbstractFormGroupDirective extends ControlContainer {
  3873. /**
  3874. * @description
  3875. * The parent control for the group
  3876. *
  3877. * @internal
  3878. */
  3879. // TODO(issue/24571): remove '!'.
  3880. _parent;
  3881. /** @nodoc */
  3882. ngOnInit() {
  3883. this._checkParentType();
  3884. // Register the group with its parent group.
  3885. this.formDirective.addFormGroup(this);
  3886. }
  3887. /** @nodoc */
  3888. ngOnDestroy() {
  3889. if (this.formDirective) {
  3890. // Remove the group from its parent group.
  3891. this.formDirective.removeFormGroup(this);
  3892. }
  3893. }
  3894. /**
  3895. * @description
  3896. * The `FormGroup` bound to this directive.
  3897. */
  3898. get control() {
  3899. return this.formDirective.getFormGroup(this);
  3900. }
  3901. /**
  3902. * @description
  3903. * The path to this group from the top-level directive.
  3904. */
  3905. get path() {
  3906. return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
  3907. }
  3908. /**
  3909. * @description
  3910. * The top-level directive for this group if present, otherwise null.
  3911. */
  3912. get formDirective() {
  3913. return this._parent ? this._parent.formDirective : null;
  3914. }
  3915. /** @internal */
  3916. _checkParentType() { }
  3917. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: AbstractFormGroupDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  3918. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: AbstractFormGroupDirective, isStandalone: false, usesInheritance: true, ngImport: i0 });
  3919. }
  3920. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: AbstractFormGroupDirective, decorators: [{
  3921. type: Directive,
  3922. args: [{
  3923. standalone: false,
  3924. }]
  3925. }] });
  3926. function modelParentException() {
  3927. return new _RuntimeError(1350 /* RuntimeErrorCode.NGMODEL_IN_FORM_GROUP */, `
  3928. ngModel cannot be used to register form controls with a parent formGroup directive. Try using
  3929. formGroup's partner directive "formControlName" instead. Example:
  3930. ${formControlNameExample}
  3931. Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:
  3932. Example:
  3933. ${ngModelWithFormGroupExample}`);
  3934. }
  3935. function formGroupNameException() {
  3936. return new _RuntimeError(1351 /* RuntimeErrorCode.NGMODEL_IN_FORM_GROUP_NAME */, `
  3937. ngModel cannot be used to register form controls with a parent formGroupName or formArrayName directive.
  3938. Option 1: Use formControlName instead of ngModel (reactive strategy):
  3939. ${formGroupNameExample}
  3940. Option 2: Update ngModel's parent be ngModelGroup (template-driven strategy):
  3941. ${ngModelGroupExample}`);
  3942. }
  3943. function missingNameException() {
  3944. return new _RuntimeError(1352 /* RuntimeErrorCode.NGMODEL_WITHOUT_NAME */, `If ngModel is used within a form tag, either the name attribute must be set or the form
  3945. control must be defined as 'standalone' in ngModelOptions.
  3946. Example 1: <input [(ngModel)]="person.firstName" name="first">
  3947. Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">`);
  3948. }
  3949. function modelGroupParentException() {
  3950. return new _RuntimeError(1353 /* RuntimeErrorCode.NGMODELGROUP_IN_FORM_GROUP */, `
  3951. ngModelGroup cannot be used with a parent formGroup directive.
  3952. Option 1: Use formGroupName instead of ngModelGroup (reactive strategy):
  3953. ${formGroupNameExample}
  3954. Option 2: Use a regular form tag instead of the formGroup directive (template-driven strategy):
  3955. ${ngModelGroupExample}`);
  3956. }
  3957. const modelGroupProvider = {
  3958. provide: ControlContainer,
  3959. useExisting: forwardRef(() => NgModelGroup),
  3960. };
  3961. /**
  3962. * @description
  3963. * Creates and binds a `FormGroup` instance to a DOM element.
  3964. *
  3965. * This directive can only be used as a child of `NgForm` (within `<form>` tags).
  3966. *
  3967. * Use this directive to validate a sub-group of your form separately from the
  3968. * rest of your form, or if some values in your domain model make more sense
  3969. * to consume together in a nested object.
  3970. *
  3971. * Provide a name for the sub-group and it will become the key
  3972. * for the sub-group in the form's full value. If you need direct access, export the directive into
  3973. * a local template variable using `ngModelGroup` (ex: `#myGroup="ngModelGroup"`).
  3974. *
  3975. * @usageNotes
  3976. *
  3977. * ### Consuming controls in a grouping
  3978. *
  3979. * The following example shows you how to combine controls together in a sub-group
  3980. * of the form.
  3981. *
  3982. * {@example forms/ts/ngModelGroup/ng_model_group_example.ts region='Component'}
  3983. *
  3984. * @ngModule FormsModule
  3985. * @publicApi
  3986. */
  3987. class NgModelGroup extends AbstractFormGroupDirective {
  3988. /**
  3989. * @description
  3990. * Tracks the name of the `NgModelGroup` bound to the directive. The name corresponds
  3991. * to a key in the parent `NgForm`.
  3992. */
  3993. name = '';
  3994. constructor(parent, validators, asyncValidators) {
  3995. super();
  3996. this._parent = parent;
  3997. this._setValidators(validators);
  3998. this._setAsyncValidators(asyncValidators);
  3999. }
  4000. /** @internal */
  4001. _checkParentType() {
  4002. if (!(this._parent instanceof NgModelGroup) &&
  4003. !(this._parent instanceof NgForm) &&
  4004. (typeof ngDevMode === 'undefined' || ngDevMode)) {
  4005. throw modelGroupParentException();
  4006. }
  4007. }
  4008. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgModelGroup, deps: [{ token: ControlContainer, host: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
  4009. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgModelGroup, isStandalone: false, selector: "[ngModelGroup]", inputs: { name: ["ngModelGroup", "name"] }, providers: [modelGroupProvider], exportAs: ["ngModelGroup"], usesInheritance: true, ngImport: i0 });
  4010. }
  4011. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgModelGroup, decorators: [{
  4012. type: Directive,
  4013. args: [{
  4014. selector: '[ngModelGroup]',
  4015. providers: [modelGroupProvider],
  4016. exportAs: 'ngModelGroup',
  4017. standalone: false,
  4018. }]
  4019. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  4020. type: Host
  4021. }, {
  4022. type: SkipSelf
  4023. }] }, { type: undefined, decorators: [{
  4024. type: Optional
  4025. }, {
  4026. type: Self
  4027. }, {
  4028. type: Inject,
  4029. args: [NG_VALIDATORS]
  4030. }] }, { type: undefined, decorators: [{
  4031. type: Optional
  4032. }, {
  4033. type: Self
  4034. }, {
  4035. type: Inject,
  4036. args: [NG_ASYNC_VALIDATORS]
  4037. }] }], propDecorators: { name: [{
  4038. type: Input,
  4039. args: ['ngModelGroup']
  4040. }] } });
  4041. const formControlBinding$1 = {
  4042. provide: NgControl,
  4043. useExisting: forwardRef(() => NgModel),
  4044. };
  4045. /**
  4046. * `ngModel` forces an additional change detection run when its inputs change:
  4047. * E.g.:
  4048. * ```html
  4049. * <div>{{myModel.valid}}</div>
  4050. * <input [(ngModel)]="myValue" #myModel="ngModel">
  4051. * ```
  4052. * I.e. `ngModel` can export itself on the element and then be used in the template.
  4053. * Normally, this would result in expressions before the `input` that use the exported directive
  4054. * to have an old value as they have been
  4055. * dirty checked before. As this is a very common case for `ngModel`, we added this second change
  4056. * detection run.
  4057. *
  4058. * Notes:
  4059. * - this is just one extra run no matter how many `ngModel`s have been changed.
  4060. * - this is a general problem when using `exportAs` for directives!
  4061. */
  4062. const resolvedPromise = (() => Promise.resolve())();
  4063. /**
  4064. * @description
  4065. * Creates a `FormControl` instance from a [domain
  4066. * model](https://en.wikipedia.org/wiki/Domain_model) and binds it to a form control element.
  4067. *
  4068. * The `FormControl` instance tracks the value, user interaction, and
  4069. * validation status of the control and keeps the view synced with the model. If used
  4070. * within a parent form, the directive also registers itself with the form as a child
  4071. * control.
  4072. *
  4073. * This directive is used by itself or as part of a larger form. Use the
  4074. * `ngModel` selector to activate it.
  4075. *
  4076. * It accepts a domain model as an optional `Input`. If you have a one-way binding
  4077. * to `ngModel` with `[]` syntax, changing the domain model's value in the component
  4078. * class sets the value in the view. If you have a two-way binding with `[()]` syntax
  4079. * (also known as 'banana-in-a-box syntax'), the value in the UI always syncs back to
  4080. * the domain model in your class.
  4081. *
  4082. * To inspect the properties of the associated `FormControl` (like the validity state),
  4083. * export the directive into a local template variable using `ngModel` as the key (ex:
  4084. * `#myVar="ngModel"`). You can then access the control using the directive's `control` property.
  4085. * However, the most commonly used properties (like `valid` and `dirty`) also exist on the control
  4086. * for direct access. See a full list of properties directly available in
  4087. * `AbstractControlDirective`.
  4088. *
  4089. * @see {@link RadioControlValueAccessor}
  4090. * @see {@link SelectControlValueAccessor}
  4091. *
  4092. * @usageNotes
  4093. *
  4094. * ### Using ngModel on a standalone control
  4095. *
  4096. * The following examples show a simple standalone control using `ngModel`:
  4097. *
  4098. * {@example forms/ts/simpleNgModel/simple_ng_model_example.ts region='Component'}
  4099. *
  4100. * When using the `ngModel` within `<form>` tags, you'll also need to supply a `name` attribute
  4101. * so that the control can be registered with the parent form under that name.
  4102. *
  4103. * In the context of a parent form, it's often unnecessary to include one-way or two-way binding,
  4104. * as the parent form syncs the value for you. You access its properties by exporting it into a
  4105. * local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where
  4106. * needed on form submission.
  4107. *
  4108. * If you do need to populate initial values into your form, using a one-way binding for
  4109. * `ngModel` tends to be sufficient as long as you use the exported form's value rather
  4110. * than the domain model's value on submit.
  4111. *
  4112. * ### Using ngModel within a form
  4113. *
  4114. * The following example shows controls using `ngModel` within a form:
  4115. *
  4116. * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
  4117. *
  4118. * ### Using a standalone ngModel within a group
  4119. *
  4120. * The following example shows you how to use a standalone ngModel control
  4121. * within a form. This controls the display of the form, but doesn't contain form data.
  4122. *
  4123. * ```html
  4124. * <form>
  4125. * <input name="login" ngModel placeholder="Login">
  4126. * <input type="checkbox" ngModel [ngModelOptions]="{standalone: true}"> Show more options?
  4127. * </form>
  4128. * <!-- form value: {login: ''} -->
  4129. * ```
  4130. *
  4131. * ### Setting the ngModel `name` attribute through options
  4132. *
  4133. * The following example shows you an alternate way to set the name attribute. Here,
  4134. * an attribute identified as name is used within a custom form control component. To still be able
  4135. * to specify the NgModel's name, you must specify it using the `ngModelOptions` input instead.
  4136. *
  4137. * ```html
  4138. * <form>
  4139. * <my-custom-form-control name="Nancy" ngModel [ngModelOptions]="{name: 'user'}">
  4140. * </my-custom-form-control>
  4141. * </form>
  4142. * <!-- form value: {user: ''} -->
  4143. * ```
  4144. *
  4145. * @ngModule FormsModule
  4146. * @publicApi
  4147. */
  4148. class NgModel extends NgControl {
  4149. _changeDetectorRef;
  4150. callSetDisabledState;
  4151. control = new FormControl();
  4152. // At runtime we coerce arbitrary values assigned to the "disabled" input to a "boolean".
  4153. // This is not reflected in the type of the property because outside of templates, consumers
  4154. // should only deal with booleans. In templates, a string is allowed for convenience and to
  4155. // match the native "disabled attribute" semantics which can be observed on input elements.
  4156. // This static member tells the compiler that values of type "string" can also be assigned
  4157. // to the input in a template.
  4158. /** @nodoc */
  4159. static ngAcceptInputType_isDisabled;
  4160. /** @internal */
  4161. _registered = false;
  4162. /**
  4163. * Internal reference to the view model value.
  4164. * @nodoc
  4165. */
  4166. viewModel;
  4167. /**
  4168. * @description
  4169. * Tracks the name bound to the directive. If a parent form exists, it
  4170. * uses this name as a key to retrieve this control's value.
  4171. */
  4172. name = '';
  4173. /**
  4174. * @description
  4175. * Tracks whether the control is disabled.
  4176. */
  4177. // TODO(issue/24571): remove '!'.
  4178. isDisabled;
  4179. /**
  4180. * @description
  4181. * Tracks the value bound to this directive.
  4182. */
  4183. model;
  4184. /**
  4185. * @description
  4186. * Tracks the configuration options for this `ngModel` instance.
  4187. *
  4188. * **name**: An alternative to setting the name attribute on the form control element. See
  4189. * the [example](api/forms/NgModel#using-ngmodel-on-a-standalone-control) for using `NgModel`
  4190. * as a standalone control.
  4191. *
  4192. * **standalone**: When set to true, the `ngModel` will not register itself with its parent form,
  4193. * and acts as if it's not in the form. Defaults to false. If no parent form exists, this option
  4194. * has no effect.
  4195. *
  4196. * **updateOn**: Defines the event upon which the form control value and validity update.
  4197. * Defaults to 'change'. Possible values: `'change'` | `'blur'` | `'submit'`.
  4198. *
  4199. */
  4200. // TODO(issue/24571): remove '!'.
  4201. options;
  4202. /**
  4203. * @description
  4204. * Event emitter for producing the `ngModelChange` event after
  4205. * the view model updates.
  4206. */
  4207. update = new EventEmitter();
  4208. constructor(parent, validators, asyncValidators, valueAccessors, _changeDetectorRef, callSetDisabledState) {
  4209. super();
  4210. this._changeDetectorRef = _changeDetectorRef;
  4211. this.callSetDisabledState = callSetDisabledState;
  4212. this._parent = parent;
  4213. this._setValidators(validators);
  4214. this._setAsyncValidators(asyncValidators);
  4215. this.valueAccessor = selectValueAccessor(this, valueAccessors);
  4216. }
  4217. /** @nodoc */
  4218. ngOnChanges(changes) {
  4219. this._checkForErrors();
  4220. if (!this._registered || 'name' in changes) {
  4221. if (this._registered) {
  4222. this._checkName();
  4223. if (this.formDirective) {
  4224. // We can't call `formDirective.removeControl(this)`, because the `name` has already been
  4225. // changed. We also can't reset the name temporarily since the logic in `removeControl`
  4226. // is inside a promise and it won't run immediately. We work around it by giving it an
  4227. // object with the same shape instead.
  4228. const oldName = changes['name'].previousValue;
  4229. this.formDirective.removeControl({ name: oldName, path: this._getPath(oldName) });
  4230. }
  4231. }
  4232. this._setUpControl();
  4233. }
  4234. if ('isDisabled' in changes) {
  4235. this._updateDisabled(changes);
  4236. }
  4237. if (isPropertyUpdated(changes, this.viewModel)) {
  4238. this._updateValue(this.model);
  4239. this.viewModel = this.model;
  4240. }
  4241. }
  4242. /** @nodoc */
  4243. ngOnDestroy() {
  4244. this.formDirective && this.formDirective.removeControl(this);
  4245. }
  4246. /**
  4247. * @description
  4248. * Returns an array that represents the path from the top-level form to this control.
  4249. * Each index is the string name of the control on that level.
  4250. */
  4251. get path() {
  4252. return this._getPath(this.name);
  4253. }
  4254. /**
  4255. * @description
  4256. * The top-level directive for this control if present, otherwise null.
  4257. */
  4258. get formDirective() {
  4259. return this._parent ? this._parent.formDirective : null;
  4260. }
  4261. /**
  4262. * @description
  4263. * Sets the new value for the view model and emits an `ngModelChange` event.
  4264. *
  4265. * @param newValue The new value emitted by `ngModelChange`.
  4266. */
  4267. viewToModelUpdate(newValue) {
  4268. this.viewModel = newValue;
  4269. this.update.emit(newValue);
  4270. }
  4271. _setUpControl() {
  4272. this._setUpdateStrategy();
  4273. this._isStandalone() ? this._setUpStandalone() : this.formDirective.addControl(this);
  4274. this._registered = true;
  4275. }
  4276. _setUpdateStrategy() {
  4277. if (this.options && this.options.updateOn != null) {
  4278. this.control._updateOn = this.options.updateOn;
  4279. }
  4280. }
  4281. _isStandalone() {
  4282. return !this._parent || !!(this.options && this.options.standalone);
  4283. }
  4284. _setUpStandalone() {
  4285. setUpControl(this.control, this, this.callSetDisabledState);
  4286. this.control.updateValueAndValidity({ emitEvent: false });
  4287. }
  4288. _checkForErrors() {
  4289. if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this._isStandalone()) {
  4290. checkParentType$1(this._parent);
  4291. }
  4292. this._checkName();
  4293. }
  4294. _checkName() {
  4295. if (this.options && this.options.name)
  4296. this.name = this.options.name;
  4297. if (!this._isStandalone() && !this.name && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  4298. throw missingNameException();
  4299. }
  4300. }
  4301. _updateValue(value) {
  4302. resolvedPromise.then(() => {
  4303. this.control.setValue(value, { emitViewToModelChange: false });
  4304. this._changeDetectorRef?.markForCheck();
  4305. });
  4306. }
  4307. _updateDisabled(changes) {
  4308. const disabledValue = changes['isDisabled'].currentValue;
  4309. // checking for 0 to avoid breaking change
  4310. const isDisabled = disabledValue !== 0 && booleanAttribute(disabledValue);
  4311. resolvedPromise.then(() => {
  4312. if (isDisabled && !this.control.disabled) {
  4313. this.control.disable();
  4314. }
  4315. else if (!isDisabled && this.control.disabled) {
  4316. this.control.enable();
  4317. }
  4318. this._changeDetectorRef?.markForCheck();
  4319. });
  4320. }
  4321. _getPath(controlName) {
  4322. return this._parent ? controlPath(controlName, this._parent) : [controlName];
  4323. }
  4324. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgModel, deps: [{ token: ControlContainer, host: true, optional: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: ChangeDetectorRef, optional: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  4325. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgModel, isStandalone: false, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: { name: "name", isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"], options: ["ngModelOptions", "options"] }, outputs: { update: "ngModelChange" }, providers: [formControlBinding$1], exportAs: ["ngModel"], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
  4326. }
  4327. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgModel, decorators: [{
  4328. type: Directive,
  4329. args: [{
  4330. selector: '[ngModel]:not([formControlName]):not([formControl])',
  4331. providers: [formControlBinding$1],
  4332. exportAs: 'ngModel',
  4333. standalone: false,
  4334. }]
  4335. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  4336. type: Optional
  4337. }, {
  4338. type: Host
  4339. }] }, { type: undefined, decorators: [{
  4340. type: Optional
  4341. }, {
  4342. type: Self
  4343. }, {
  4344. type: Inject,
  4345. args: [NG_VALIDATORS]
  4346. }] }, { type: undefined, decorators: [{
  4347. type: Optional
  4348. }, {
  4349. type: Self
  4350. }, {
  4351. type: Inject,
  4352. args: [NG_ASYNC_VALIDATORS]
  4353. }] }, { type: undefined, decorators: [{
  4354. type: Optional
  4355. }, {
  4356. type: Self
  4357. }, {
  4358. type: Inject,
  4359. args: [NG_VALUE_ACCESSOR]
  4360. }] }, { type: i0.ChangeDetectorRef, decorators: [{
  4361. type: Optional
  4362. }, {
  4363. type: Inject,
  4364. args: [ChangeDetectorRef]
  4365. }] }, { type: undefined, decorators: [{
  4366. type: Optional
  4367. }, {
  4368. type: Inject,
  4369. args: [CALL_SET_DISABLED_STATE]
  4370. }] }], propDecorators: { name: [{
  4371. type: Input
  4372. }], isDisabled: [{
  4373. type: Input,
  4374. args: ['disabled']
  4375. }], model: [{
  4376. type: Input,
  4377. args: ['ngModel']
  4378. }], options: [{
  4379. type: Input,
  4380. args: ['ngModelOptions']
  4381. }], update: [{
  4382. type: Output,
  4383. args: ['ngModelChange']
  4384. }] } });
  4385. function checkParentType$1(parent) {
  4386. if (!(parent instanceof NgModelGroup) && parent instanceof AbstractFormGroupDirective) {
  4387. throw formGroupNameException();
  4388. }
  4389. else if (!(parent instanceof NgModelGroup) && !(parent instanceof NgForm)) {
  4390. throw modelParentException();
  4391. }
  4392. }
  4393. /**
  4394. * @description
  4395. *
  4396. * Adds `novalidate` attribute to all forms by default.
  4397. *
  4398. * `novalidate` is used to disable browser's native form validation.
  4399. *
  4400. * If you want to use native validation with Angular forms, just add `ngNativeValidate` attribute:
  4401. *
  4402. * ```html
  4403. * <form ngNativeValidate></form>
  4404. * ```
  4405. *
  4406. * @publicApi
  4407. * @ngModule ReactiveFormsModule
  4408. * @ngModule FormsModule
  4409. */
  4410. class ɵNgNoValidate {
  4411. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵNgNoValidate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  4412. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: ɵNgNoValidate, isStandalone: false, selector: "form:not([ngNoForm]):not([ngNativeValidate])", host: { attributes: { "novalidate": "" } }, ngImport: i0 });
  4413. }
  4414. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵNgNoValidate, decorators: [{
  4415. type: Directive,
  4416. args: [{
  4417. selector: 'form:not([ngNoForm]):not([ngNativeValidate])',
  4418. host: { 'novalidate': '' },
  4419. standalone: false,
  4420. }]
  4421. }] });
  4422. const NUMBER_VALUE_ACCESSOR = {
  4423. provide: NG_VALUE_ACCESSOR,
  4424. useExisting: forwardRef(() => NumberValueAccessor),
  4425. multi: true,
  4426. };
  4427. /**
  4428. * @description
  4429. * The `ControlValueAccessor` for writing a number value and listening to number input changes.
  4430. * The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
  4431. * directives.
  4432. *
  4433. * @usageNotes
  4434. *
  4435. * ### Using a number input with a reactive form.
  4436. *
  4437. * The following example shows how to use a number input with a reactive form.
  4438. *
  4439. * ```ts
  4440. * const totalCountControl = new FormControl();
  4441. * ```
  4442. *
  4443. * ```html
  4444. * <input type="number" [formControl]="totalCountControl">
  4445. * ```
  4446. *
  4447. * @ngModule ReactiveFormsModule
  4448. * @ngModule FormsModule
  4449. * @publicApi
  4450. */
  4451. class NumberValueAccessor extends BuiltInControlValueAccessor {
  4452. /**
  4453. * Sets the "value" property on the input element.
  4454. * @nodoc
  4455. */
  4456. writeValue(value) {
  4457. // The value needs to be normalized for IE9, otherwise it is set to 'null' when null
  4458. const normalizedValue = value == null ? '' : value;
  4459. this.setProperty('value', normalizedValue);
  4460. }
  4461. /**
  4462. * Registers a function called when the control value changes.
  4463. * @nodoc
  4464. */
  4465. registerOnChange(fn) {
  4466. this.onChange = (value) => {
  4467. fn(value == '' ? null : parseFloat(value));
  4468. };
  4469. }
  4470. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NumberValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  4471. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NumberValueAccessor, isStandalone: false, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]", host: { listeners: { "input": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [NUMBER_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  4472. }
  4473. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NumberValueAccessor, decorators: [{
  4474. type: Directive,
  4475. args: [{
  4476. selector: 'input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]',
  4477. host: { '(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
  4478. providers: [NUMBER_VALUE_ACCESSOR],
  4479. standalone: false,
  4480. }]
  4481. }] });
  4482. const RADIO_VALUE_ACCESSOR = {
  4483. provide: NG_VALUE_ACCESSOR,
  4484. useExisting: forwardRef(() => RadioControlValueAccessor),
  4485. multi: true,
  4486. };
  4487. function throwNameError() {
  4488. throw new _RuntimeError(1202 /* RuntimeErrorCode.NAME_AND_FORM_CONTROL_NAME_MUST_MATCH */, `
  4489. If you define both a name and a formControlName attribute on your radio button, their values
  4490. must match. Ex: <input type="radio" formControlName="food" name="food">
  4491. `);
  4492. }
  4493. /**
  4494. * @description
  4495. * Class used by Angular to track radio buttons. For internal use only.
  4496. */
  4497. class RadioControlRegistry {
  4498. _accessors = [];
  4499. /**
  4500. * @description
  4501. * Adds a control to the internal registry. For internal use only.
  4502. */
  4503. add(control, accessor) {
  4504. this._accessors.push([control, accessor]);
  4505. }
  4506. /**
  4507. * @description
  4508. * Removes a control from the internal registry. For internal use only.
  4509. */
  4510. remove(accessor) {
  4511. for (let i = this._accessors.length - 1; i >= 0; --i) {
  4512. if (this._accessors[i][1] === accessor) {
  4513. this._accessors.splice(i, 1);
  4514. return;
  4515. }
  4516. }
  4517. }
  4518. /**
  4519. * @description
  4520. * Selects a radio button. For internal use only.
  4521. */
  4522. select(accessor) {
  4523. this._accessors.forEach((c) => {
  4524. if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
  4525. c[1].fireUncheck(accessor.value);
  4526. }
  4527. });
  4528. }
  4529. _isSameGroup(controlPair, accessor) {
  4530. if (!controlPair[0].control)
  4531. return false;
  4532. return (controlPair[0]._parent === accessor._control._parent && controlPair[1].name === accessor.name);
  4533. }
  4534. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioControlRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
  4535. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioControlRegistry, providedIn: 'root' });
  4536. }
  4537. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioControlRegistry, decorators: [{
  4538. type: Injectable,
  4539. args: [{ providedIn: 'root' }]
  4540. }] });
  4541. /**
  4542. * @description
  4543. * The `ControlValueAccessor` for writing radio control values and listening to radio control
  4544. * changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
  4545. * `NgModel` directives.
  4546. *
  4547. * @usageNotes
  4548. *
  4549. * ### Using radio buttons with reactive form directives
  4550. *
  4551. * The follow example shows how to use radio buttons in a reactive form. When using radio buttons in
  4552. * a reactive form, radio buttons in the same group should have the same `formControlName`.
  4553. * Providing a `name` attribute is optional.
  4554. *
  4555. * {@example forms/ts/reactiveRadioButtons/reactive_radio_button_example.ts region='Reactive'}
  4556. *
  4557. * @ngModule ReactiveFormsModule
  4558. * @ngModule FormsModule
  4559. * @publicApi
  4560. */
  4561. class RadioControlValueAccessor extends BuiltInControlValueAccessor {
  4562. _registry;
  4563. _injector;
  4564. /** @internal */
  4565. // TODO(issue/24571): remove '!'.
  4566. _state;
  4567. /** @internal */
  4568. // TODO(issue/24571): remove '!'.
  4569. _control;
  4570. /** @internal */
  4571. // TODO(issue/24571): remove '!'.
  4572. _fn;
  4573. setDisabledStateFired = false;
  4574. /**
  4575. * The registered callback function called when a change event occurs on the input element.
  4576. * Note: we declare `onChange` here (also used as host listener) as a function with no arguments
  4577. * to override the `onChange` function (which expects 1 argument) in the parent
  4578. * `BaseControlValueAccessor` class.
  4579. * @nodoc
  4580. */
  4581. onChange = () => { };
  4582. /**
  4583. * @description
  4584. * Tracks the name of the radio input element.
  4585. */
  4586. // TODO(issue/24571): remove '!'.
  4587. name;
  4588. /**
  4589. * @description
  4590. * Tracks the name of the `FormControl` bound to the directive. The name corresponds
  4591. * to a key in the parent `FormGroup` or `FormArray`.
  4592. */
  4593. // TODO(issue/24571): remove '!'.
  4594. formControlName;
  4595. /**
  4596. * @description
  4597. * Tracks the value of the radio input element
  4598. */
  4599. value;
  4600. callSetDisabledState = inject(CALL_SET_DISABLED_STATE, { optional: true }) ?? setDisabledStateDefault;
  4601. constructor(renderer, elementRef, _registry, _injector) {
  4602. super(renderer, elementRef);
  4603. this._registry = _registry;
  4604. this._injector = _injector;
  4605. }
  4606. /** @nodoc */
  4607. ngOnInit() {
  4608. this._control = this._injector.get(NgControl);
  4609. this._checkName();
  4610. this._registry.add(this._control, this);
  4611. }
  4612. /** @nodoc */
  4613. ngOnDestroy() {
  4614. this._registry.remove(this);
  4615. }
  4616. /**
  4617. * Sets the "checked" property value on the radio input element.
  4618. * @nodoc
  4619. */
  4620. writeValue(value) {
  4621. this._state = value === this.value;
  4622. this.setProperty('checked', this._state);
  4623. }
  4624. /**
  4625. * Registers a function called when the control value changes.
  4626. * @nodoc
  4627. */
  4628. registerOnChange(fn) {
  4629. this._fn = fn;
  4630. this.onChange = () => {
  4631. fn(this.value);
  4632. this._registry.select(this);
  4633. };
  4634. }
  4635. /** @nodoc */
  4636. setDisabledState(isDisabled) {
  4637. /**
  4638. * `setDisabledState` is supposed to be called whenever the disabled state of a control changes,
  4639. * including upon control creation. However, a longstanding bug caused the method to not fire
  4640. * when an *enabled* control was attached. This bug was fixed in v15 in #47576.
  4641. *
  4642. * This had a side effect: previously, it was possible to instantiate a reactive form control
  4643. * with `[attr.disabled]=true`, even though the corresponding control was enabled in the
  4644. * model. This resulted in a mismatch between the model and the DOM. Now, because
  4645. * `setDisabledState` is always called, the value in the DOM will be immediately overwritten
  4646. * with the "correct" enabled value.
  4647. *
  4648. * However, the fix also created an exceptional case: radio buttons. Because Reactive Forms
  4649. * models the entire group of radio buttons as a single `FormControl`, there is no way to
  4650. * control the disabled state for individual radios, so they can no longer be configured as
  4651. * disabled. Thus, we keep the old behavior for radio buttons, so that `[attr.disabled]`
  4652. * continues to work. Specifically, we drop the first call to `setDisabledState` if `disabled`
  4653. * is `false`, and we are not in legacy mode.
  4654. */
  4655. if (this.setDisabledStateFired ||
  4656. isDisabled ||
  4657. this.callSetDisabledState === 'whenDisabledForLegacyCode') {
  4658. this.setProperty('disabled', isDisabled);
  4659. }
  4660. this.setDisabledStateFired = true;
  4661. }
  4662. /**
  4663. * Sets the "value" on the radio input element and unchecks it.
  4664. *
  4665. * @param value
  4666. */
  4667. fireUncheck(value) {
  4668. this.writeValue(value);
  4669. }
  4670. _checkName() {
  4671. if (this.name &&
  4672. this.formControlName &&
  4673. this.name !== this.formControlName &&
  4674. (typeof ngDevMode === 'undefined' || ngDevMode)) {
  4675. throwNameError();
  4676. }
  4677. if (!this.name && this.formControlName)
  4678. this.name = this.formControlName;
  4679. }
  4680. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioControlValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: RadioControlRegistry }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive });
  4681. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: RadioControlValueAccessor, isStandalone: false, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: { name: "name", formControlName: "formControlName", value: "value" }, host: { listeners: { "change": "onChange()", "blur": "onTouched()" } }, providers: [RADIO_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  4682. }
  4683. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioControlValueAccessor, decorators: [{
  4684. type: Directive,
  4685. args: [{
  4686. selector: 'input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]',
  4687. host: { '(change)': 'onChange()', '(blur)': 'onTouched()' },
  4688. providers: [RADIO_VALUE_ACCESSOR],
  4689. standalone: false,
  4690. }]
  4691. }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: RadioControlRegistry }, { type: i0.Injector }], propDecorators: { name: [{
  4692. type: Input
  4693. }], formControlName: [{
  4694. type: Input
  4695. }], value: [{
  4696. type: Input
  4697. }] } });
  4698. const RANGE_VALUE_ACCESSOR = {
  4699. provide: NG_VALUE_ACCESSOR,
  4700. useExisting: forwardRef(() => RangeValueAccessor),
  4701. multi: true,
  4702. };
  4703. /**
  4704. * @description
  4705. * The `ControlValueAccessor` for writing a range value and listening to range input changes.
  4706. * The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
  4707. * directives.
  4708. *
  4709. * @usageNotes
  4710. *
  4711. * ### Using a range input with a reactive form
  4712. *
  4713. * The following example shows how to use a range input with a reactive form.
  4714. *
  4715. * ```ts
  4716. * const ageControl = new FormControl();
  4717. * ```
  4718. *
  4719. * ```html
  4720. * <input type="range" [formControl]="ageControl">
  4721. * ```
  4722. *
  4723. * @ngModule ReactiveFormsModule
  4724. * @ngModule FormsModule
  4725. * @publicApi
  4726. */
  4727. class RangeValueAccessor extends BuiltInControlValueAccessor {
  4728. /**
  4729. * Sets the "value" property on the input element.
  4730. * @nodoc
  4731. */
  4732. writeValue(value) {
  4733. this.setProperty('value', parseFloat(value));
  4734. }
  4735. /**
  4736. * Registers a function called when the control value changes.
  4737. * @nodoc
  4738. */
  4739. registerOnChange(fn) {
  4740. this.onChange = (value) => {
  4741. fn(value == '' ? null : parseFloat(value));
  4742. };
  4743. }
  4744. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RangeValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  4745. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: RangeValueAccessor, isStandalone: false, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]", host: { listeners: { "change": "onChange($event.target.value)", "input": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [RANGE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  4746. }
  4747. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RangeValueAccessor, decorators: [{
  4748. type: Directive,
  4749. args: [{
  4750. selector: 'input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]',
  4751. host: {
  4752. '(change)': 'onChange($event.target.value)',
  4753. '(input)': 'onChange($event.target.value)',
  4754. '(blur)': 'onTouched()',
  4755. },
  4756. providers: [RANGE_VALUE_ACCESSOR],
  4757. standalone: false,
  4758. }]
  4759. }] });
  4760. /**
  4761. * Token to provide to turn off the ngModel warning on formControl and formControlName.
  4762. */
  4763. const NG_MODEL_WITH_FORM_CONTROL_WARNING = new InjectionToken(ngDevMode ? 'NgModelWithFormControlWarning' : '');
  4764. const formControlBinding = {
  4765. provide: NgControl,
  4766. useExisting: forwardRef(() => FormControlDirective),
  4767. };
  4768. /**
  4769. * @description
  4770. * Synchronizes a standalone `FormControl` instance to a form control element.
  4771. *
  4772. * Note that support for using the `ngModel` input property and `ngModelChange` event with reactive
  4773. * form directives was deprecated in Angular v6 and is scheduled for removal in
  4774. * a future version of Angular.
  4775. *
  4776. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  4777. * @see {@link FormControl}
  4778. * @see {@link AbstractControl}
  4779. *
  4780. * @usageNotes
  4781. *
  4782. * The following example shows how to register a standalone control and set its value.
  4783. *
  4784. * {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
  4785. *
  4786. * @ngModule ReactiveFormsModule
  4787. * @publicApi
  4788. */
  4789. class FormControlDirective extends NgControl {
  4790. _ngModelWarningConfig;
  4791. callSetDisabledState;
  4792. /**
  4793. * Internal reference to the view model value.
  4794. * @nodoc
  4795. */
  4796. viewModel;
  4797. /**
  4798. * @description
  4799. * Tracks the `FormControl` instance bound to the directive.
  4800. */
  4801. // TODO(issue/24571): remove '!'.
  4802. form;
  4803. /**
  4804. * @description
  4805. * Triggers a warning in dev mode that this input should not be used with reactive forms.
  4806. */
  4807. set isDisabled(isDisabled) {
  4808. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  4809. console.warn(disabledAttrWarning);
  4810. }
  4811. }
  4812. // TODO(kara): remove next 4 properties once deprecation period is over
  4813. /** @deprecated as of v6 */
  4814. model;
  4815. /** @deprecated as of v6 */
  4816. update = new EventEmitter();
  4817. /**
  4818. * @description
  4819. * Static property used to track whether any ngModel warnings have been sent across
  4820. * all instances of FormControlDirective. Used to support warning config of "once".
  4821. *
  4822. * @internal
  4823. */
  4824. static _ngModelWarningSentOnce = false;
  4825. /**
  4826. * @description
  4827. * Instance property used to track whether an ngModel warning has been sent out for this
  4828. * particular `FormControlDirective` instance. Used to support warning config of "always".
  4829. *
  4830. * @internal
  4831. */
  4832. _ngModelWarningSent = false;
  4833. constructor(validators, asyncValidators, valueAccessors, _ngModelWarningConfig, callSetDisabledState) {
  4834. super();
  4835. this._ngModelWarningConfig = _ngModelWarningConfig;
  4836. this.callSetDisabledState = callSetDisabledState;
  4837. this._setValidators(validators);
  4838. this._setAsyncValidators(asyncValidators);
  4839. this.valueAccessor = selectValueAccessor(this, valueAccessors);
  4840. }
  4841. /** @nodoc */
  4842. ngOnChanges(changes) {
  4843. if (this._isControlChanged(changes)) {
  4844. const previousForm = changes['form'].previousValue;
  4845. if (previousForm) {
  4846. cleanUpControl(previousForm, this, /* validateControlPresenceOnChange */ false);
  4847. }
  4848. setUpControl(this.form, this, this.callSetDisabledState);
  4849. this.form.updateValueAndValidity({ emitEvent: false });
  4850. }
  4851. if (isPropertyUpdated(changes, this.viewModel)) {
  4852. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  4853. _ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
  4854. }
  4855. this.form.setValue(this.model);
  4856. this.viewModel = this.model;
  4857. }
  4858. }
  4859. /** @nodoc */
  4860. ngOnDestroy() {
  4861. if (this.form) {
  4862. cleanUpControl(this.form, this, /* validateControlPresenceOnChange */ false);
  4863. }
  4864. }
  4865. /**
  4866. * @description
  4867. * Returns an array that represents the path from the top-level form to this control.
  4868. * Each index is the string name of the control on that level.
  4869. */
  4870. get path() {
  4871. return [];
  4872. }
  4873. /**
  4874. * @description
  4875. * The `FormControl` bound to this directive.
  4876. */
  4877. get control() {
  4878. return this.form;
  4879. }
  4880. /**
  4881. * @description
  4882. * Sets the new value for the view model and emits an `ngModelChange` event.
  4883. *
  4884. * @param newValue The new value for the view model.
  4885. */
  4886. viewToModelUpdate(newValue) {
  4887. this.viewModel = newValue;
  4888. this.update.emit(newValue);
  4889. }
  4890. _isControlChanged(changes) {
  4891. return changes.hasOwnProperty('form');
  4892. }
  4893. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormControlDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  4894. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: FormControlDirective, isStandalone: false, selector: "[formControl]", inputs: { form: ["formControl", "form"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [formControlBinding], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
  4895. }
  4896. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormControlDirective, decorators: [{
  4897. type: Directive,
  4898. args: [{
  4899. selector: '[formControl]',
  4900. providers: [formControlBinding],
  4901. exportAs: 'ngForm',
  4902. standalone: false,
  4903. }]
  4904. }], ctorParameters: () => [{ type: undefined, decorators: [{
  4905. type: Optional
  4906. }, {
  4907. type: Self
  4908. }, {
  4909. type: Inject,
  4910. args: [NG_VALIDATORS]
  4911. }] }, { type: undefined, decorators: [{
  4912. type: Optional
  4913. }, {
  4914. type: Self
  4915. }, {
  4916. type: Inject,
  4917. args: [NG_ASYNC_VALIDATORS]
  4918. }] }, { type: undefined, decorators: [{
  4919. type: Optional
  4920. }, {
  4921. type: Self
  4922. }, {
  4923. type: Inject,
  4924. args: [NG_VALUE_ACCESSOR]
  4925. }] }, { type: undefined, decorators: [{
  4926. type: Optional
  4927. }, {
  4928. type: Inject,
  4929. args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
  4930. }] }, { type: undefined, decorators: [{
  4931. type: Optional
  4932. }, {
  4933. type: Inject,
  4934. args: [CALL_SET_DISABLED_STATE]
  4935. }] }], propDecorators: { form: [{
  4936. type: Input,
  4937. args: ['formControl']
  4938. }], isDisabled: [{
  4939. type: Input,
  4940. args: ['disabled']
  4941. }], model: [{
  4942. type: Input,
  4943. args: ['ngModel']
  4944. }], update: [{
  4945. type: Output,
  4946. args: ['ngModelChange']
  4947. }] } });
  4948. const formDirectiveProvider = {
  4949. provide: ControlContainer,
  4950. useExisting: forwardRef(() => FormGroupDirective),
  4951. };
  4952. /**
  4953. * @description
  4954. *
  4955. * Binds an existing `FormGroup` or `FormRecord` to a DOM element.
  4956. *
  4957. * This directive accepts an existing `FormGroup` instance. It will then use this
  4958. * `FormGroup` instance to match any child `FormControl`, `FormGroup`/`FormRecord`,
  4959. * and `FormArray` instances to child `FormControlName`, `FormGroupName`,
  4960. * and `FormArrayName` directives.
  4961. *
  4962. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  4963. * @see {@link AbstractControl}
  4964. *
  4965. * @usageNotes
  4966. * ### Register Form Group
  4967. *
  4968. * The following example registers a `FormGroup` with first name and last name controls,
  4969. * and listens for the *ngSubmit* event when the button is clicked.
  4970. *
  4971. * {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
  4972. *
  4973. * @ngModule ReactiveFormsModule
  4974. * @publicApi
  4975. */
  4976. class FormGroupDirective extends ControlContainer {
  4977. callSetDisabledState;
  4978. /**
  4979. * @description
  4980. * Reports whether the form submission has been triggered.
  4981. */
  4982. get submitted() {
  4983. return untracked(this._submittedReactive);
  4984. }
  4985. // TODO(atscott): Remove once invalid API usage is cleaned up internally
  4986. set submitted(value) {
  4987. this._submittedReactive.set(value);
  4988. }
  4989. /** @internal */
  4990. _submitted = computed(() => this._submittedReactive());
  4991. _submittedReactive = signal(false);
  4992. /**
  4993. * Reference to an old form group input value, which is needed to cleanup
  4994. * old instance in case it was replaced with a new one.
  4995. */
  4996. _oldForm;
  4997. /**
  4998. * Callback that should be invoked when controls in FormGroup or FormArray collection change
  4999. * (added or removed). This callback triggers corresponding DOM updates.
  5000. */
  5001. _onCollectionChange = () => this._updateDomValue();
  5002. /**
  5003. * @description
  5004. * Tracks the list of added `FormControlName` instances
  5005. */
  5006. directives = [];
  5007. /**
  5008. * @description
  5009. * Tracks the `FormGroup` bound to this directive.
  5010. */
  5011. form = null;
  5012. /**
  5013. * @description
  5014. * Emits an event when the form submission has been triggered.
  5015. */
  5016. ngSubmit = new EventEmitter();
  5017. constructor(validators, asyncValidators, callSetDisabledState) {
  5018. super();
  5019. this.callSetDisabledState = callSetDisabledState;
  5020. this._setValidators(validators);
  5021. this._setAsyncValidators(asyncValidators);
  5022. }
  5023. /** @nodoc */
  5024. ngOnChanges(changes) {
  5025. if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this.form) {
  5026. throw missingFormException();
  5027. }
  5028. if (changes.hasOwnProperty('form')) {
  5029. this._updateValidators();
  5030. this._updateDomValue();
  5031. this._updateRegistrations();
  5032. this._oldForm = this.form;
  5033. }
  5034. }
  5035. /** @nodoc */
  5036. ngOnDestroy() {
  5037. if (this.form) {
  5038. cleanUpValidators(this.form, this);
  5039. // Currently the `onCollectionChange` callback is rewritten each time the
  5040. // `_registerOnCollectionChange` function is invoked. The implication is that cleanup should
  5041. // happen *only* when the `onCollectionChange` callback was set by this directive instance.
  5042. // Otherwise it might cause overriding a callback of some other directive instances. We should
  5043. // consider updating this logic later to make it similar to how `onChange` callbacks are
  5044. // handled, see https://github.com/angular/angular/issues/39732 for additional info.
  5045. if (this.form._onCollectionChange === this._onCollectionChange) {
  5046. this.form._registerOnCollectionChange(() => { });
  5047. }
  5048. }
  5049. }
  5050. /**
  5051. * @description
  5052. * Returns this directive's instance.
  5053. */
  5054. get formDirective() {
  5055. return this;
  5056. }
  5057. /**
  5058. * @description
  5059. * Returns the `FormGroup` bound to this directive.
  5060. */
  5061. get control() {
  5062. return this.form;
  5063. }
  5064. /**
  5065. * @description
  5066. * Returns an array representing the path to this group. Because this directive
  5067. * always lives at the top level of a form, it always an empty array.
  5068. */
  5069. get path() {
  5070. return [];
  5071. }
  5072. /**
  5073. * @description
  5074. * Method that sets up the control directive in this group, re-calculates its value
  5075. * and validity, and adds the instance to the internal list of directives.
  5076. *
  5077. * @param dir The `FormControlName` directive instance.
  5078. */
  5079. addControl(dir) {
  5080. const ctrl = this.form.get(dir.path);
  5081. setUpControl(ctrl, dir, this.callSetDisabledState);
  5082. ctrl.updateValueAndValidity({ emitEvent: false });
  5083. this.directives.push(dir);
  5084. return ctrl;
  5085. }
  5086. /**
  5087. * @description
  5088. * Retrieves the `FormControl` instance from the provided `FormControlName` directive
  5089. *
  5090. * @param dir The `FormControlName` directive instance.
  5091. */
  5092. getControl(dir) {
  5093. return this.form.get(dir.path);
  5094. }
  5095. /**
  5096. * @description
  5097. * Removes the `FormControlName` instance from the internal list of directives
  5098. *
  5099. * @param dir The `FormControlName` directive instance.
  5100. */
  5101. removeControl(dir) {
  5102. cleanUpControl(dir.control || null, dir, /* validateControlPresenceOnChange */ false);
  5103. removeListItem$1(this.directives, dir);
  5104. }
  5105. /**
  5106. * Adds a new `FormGroupName` directive instance to the form.
  5107. *
  5108. * @param dir The `FormGroupName` directive instance.
  5109. */
  5110. addFormGroup(dir) {
  5111. this._setUpFormContainer(dir);
  5112. }
  5113. /**
  5114. * Performs the necessary cleanup when a `FormGroupName` directive instance is removed from the
  5115. * view.
  5116. *
  5117. * @param dir The `FormGroupName` directive instance.
  5118. */
  5119. removeFormGroup(dir) {
  5120. this._cleanUpFormContainer(dir);
  5121. }
  5122. /**
  5123. * @description
  5124. * Retrieves the `FormGroup` for a provided `FormGroupName` directive instance
  5125. *
  5126. * @param dir The `FormGroupName` directive instance.
  5127. */
  5128. getFormGroup(dir) {
  5129. return this.form.get(dir.path);
  5130. }
  5131. /**
  5132. * Performs the necessary setup when a `FormArrayName` directive instance is added to the view.
  5133. *
  5134. * @param dir The `FormArrayName` directive instance.
  5135. */
  5136. addFormArray(dir) {
  5137. this._setUpFormContainer(dir);
  5138. }
  5139. /**
  5140. * Performs the necessary cleanup when a `FormArrayName` directive instance is removed from the
  5141. * view.
  5142. *
  5143. * @param dir The `FormArrayName` directive instance.
  5144. */
  5145. removeFormArray(dir) {
  5146. this._cleanUpFormContainer(dir);
  5147. }
  5148. /**
  5149. * @description
  5150. * Retrieves the `FormArray` for a provided `FormArrayName` directive instance.
  5151. *
  5152. * @param dir The `FormArrayName` directive instance.
  5153. */
  5154. getFormArray(dir) {
  5155. return this.form.get(dir.path);
  5156. }
  5157. /**
  5158. * Sets the new value for the provided `FormControlName` directive.
  5159. *
  5160. * @param dir The `FormControlName` directive instance.
  5161. * @param value The new value for the directive's control.
  5162. */
  5163. updateModel(dir, value) {
  5164. const ctrl = this.form.get(dir.path);
  5165. ctrl.setValue(value);
  5166. }
  5167. /**
  5168. * @description
  5169. * Method called with the "submit" event is triggered on the form.
  5170. * Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
  5171. *
  5172. * @param $event The "submit" event object
  5173. */
  5174. onSubmit($event) {
  5175. this._submittedReactive.set(true);
  5176. syncPendingControls(this.form, this.directives);
  5177. this.ngSubmit.emit($event);
  5178. this.form._events.next(new FormSubmittedEvent(this.control));
  5179. // Forms with `method="dialog"` have some special behavior that won't reload the page and that
  5180. // shouldn't be prevented. Note that we need to null check the `event` and the `target`, because
  5181. // some internal apps call this method directly with the wrong arguments.
  5182. return $event?.target?.method === 'dialog';
  5183. }
  5184. /**
  5185. * @description
  5186. * Method called when the "reset" event is triggered on the form.
  5187. */
  5188. onReset() {
  5189. this.resetForm();
  5190. }
  5191. /**
  5192. * @description
  5193. * Resets the form to an initial value and resets its submitted status.
  5194. *
  5195. * @param value The new value for the form.
  5196. */
  5197. resetForm(value = undefined) {
  5198. this.form.reset(value);
  5199. this._submittedReactive.set(false);
  5200. this.form._events.next(new FormResetEvent(this.form));
  5201. }
  5202. /** @internal */
  5203. _updateDomValue() {
  5204. this.directives.forEach((dir) => {
  5205. const oldCtrl = dir.control;
  5206. const newCtrl = this.form.get(dir.path);
  5207. if (oldCtrl !== newCtrl) {
  5208. // Note: the value of the `dir.control` may not be defined, for example when it's a first
  5209. // `FormControl` that is added to a `FormGroup` instance (via `addControl` call).
  5210. cleanUpControl(oldCtrl || null, dir);
  5211. // Check whether new control at the same location inside the corresponding `FormGroup` is an
  5212. // instance of `FormControl` and perform control setup only if that's the case.
  5213. // Note: we don't need to clear the list of directives (`this.directives`) here, it would be
  5214. // taken care of in the `removeControl` method invoked when corresponding `formControlName`
  5215. // directive instance is being removed (invoked from `FormControlName.ngOnDestroy`).
  5216. if (isFormControl(newCtrl)) {
  5217. setUpControl(newCtrl, dir, this.callSetDisabledState);
  5218. dir.control = newCtrl;
  5219. }
  5220. }
  5221. });
  5222. this.form._updateTreeValidity({ emitEvent: false });
  5223. }
  5224. _setUpFormContainer(dir) {
  5225. const ctrl = this.form.get(dir.path);
  5226. setUpFormContainer(ctrl, dir);
  5227. // NOTE: this operation looks unnecessary in case no new validators were added in
  5228. // `setUpFormContainer` call. Consider updating this code to match the logic in
  5229. // `_cleanUpFormContainer` function.
  5230. ctrl.updateValueAndValidity({ emitEvent: false });
  5231. }
  5232. _cleanUpFormContainer(dir) {
  5233. if (this.form) {
  5234. const ctrl = this.form.get(dir.path);
  5235. if (ctrl) {
  5236. const isControlUpdated = cleanUpFormContainer(ctrl, dir);
  5237. if (isControlUpdated) {
  5238. // Run validity check only in case a control was updated (i.e. view validators were
  5239. // removed) as removing view validators might cause validity to change.
  5240. ctrl.updateValueAndValidity({ emitEvent: false });
  5241. }
  5242. }
  5243. }
  5244. }
  5245. _updateRegistrations() {
  5246. this.form._registerOnCollectionChange(this._onCollectionChange);
  5247. if (this._oldForm) {
  5248. this._oldForm._registerOnCollectionChange(() => { });
  5249. }
  5250. }
  5251. _updateValidators() {
  5252. setUpValidators(this.form, this);
  5253. if (this._oldForm) {
  5254. cleanUpValidators(this._oldForm, this);
  5255. }
  5256. }
  5257. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormGroupDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  5258. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: FormGroupDirective, isStandalone: false, selector: "[formGroup]", inputs: { form: ["formGroup", "form"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
  5259. }
  5260. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormGroupDirective, decorators: [{
  5261. type: Directive,
  5262. args: [{
  5263. selector: '[formGroup]',
  5264. providers: [formDirectiveProvider],
  5265. host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
  5266. exportAs: 'ngForm',
  5267. standalone: false,
  5268. }]
  5269. }], ctorParameters: () => [{ type: undefined, decorators: [{
  5270. type: Optional
  5271. }, {
  5272. type: Self
  5273. }, {
  5274. type: Inject,
  5275. args: [NG_VALIDATORS]
  5276. }] }, { type: undefined, decorators: [{
  5277. type: Optional
  5278. }, {
  5279. type: Self
  5280. }, {
  5281. type: Inject,
  5282. args: [NG_ASYNC_VALIDATORS]
  5283. }] }, { type: undefined, decorators: [{
  5284. type: Optional
  5285. }, {
  5286. type: Inject,
  5287. args: [CALL_SET_DISABLED_STATE]
  5288. }] }], propDecorators: { form: [{
  5289. type: Input,
  5290. args: ['formGroup']
  5291. }], ngSubmit: [{
  5292. type: Output
  5293. }] } });
  5294. const formGroupNameProvider = {
  5295. provide: ControlContainer,
  5296. useExisting: forwardRef(() => FormGroupName),
  5297. };
  5298. /**
  5299. * @description
  5300. *
  5301. * Syncs a nested `FormGroup` or `FormRecord` to a DOM element.
  5302. *
  5303. * This directive can only be used with a parent `FormGroupDirective`.
  5304. *
  5305. * It accepts the string name of the nested `FormGroup` or `FormRecord` to link, and
  5306. * looks for a `FormGroup` or `FormRecord` registered with that name in the parent
  5307. * `FormGroup` instance you passed into `FormGroupDirective`.
  5308. *
  5309. * Use nested form groups to validate a sub-group of a
  5310. * form separately from the rest or to group the values of certain
  5311. * controls into their own nested object.
  5312. *
  5313. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  5314. *
  5315. * @usageNotes
  5316. *
  5317. * ### Access the group by name
  5318. *
  5319. * The following example uses the `AbstractControl.get` method to access the
  5320. * associated `FormGroup`
  5321. *
  5322. * ```ts
  5323. * this.form.get('name');
  5324. * ```
  5325. *
  5326. * ### Access individual controls in the group
  5327. *
  5328. * The following example uses the `AbstractControl.get` method to access
  5329. * individual controls within the group using dot syntax.
  5330. *
  5331. * ```ts
  5332. * this.form.get('name.first');
  5333. * ```
  5334. *
  5335. * ### Register a nested `FormGroup`.
  5336. *
  5337. * The following example registers a nested *name* `FormGroup` within an existing `FormGroup`,
  5338. * and provides methods to retrieve the nested `FormGroup` and individual controls.
  5339. *
  5340. * {@example forms/ts/nestedFormGroup/nested_form_group_example.ts region='Component'}
  5341. *
  5342. * @ngModule ReactiveFormsModule
  5343. * @publicApi
  5344. */
  5345. class FormGroupName extends AbstractFormGroupDirective {
  5346. /**
  5347. * @description
  5348. * Tracks the name of the `FormGroup` bound to the directive. The name corresponds
  5349. * to a key in the parent `FormGroup` or `FormArray`.
  5350. * Accepts a name as a string or a number.
  5351. * The name in the form of a string is useful for individual forms,
  5352. * while the numerical form allows for form groups to be bound
  5353. * to indices when iterating over groups in a `FormArray`.
  5354. */
  5355. name = null;
  5356. constructor(parent, validators, asyncValidators) {
  5357. super();
  5358. this._parent = parent;
  5359. this._setValidators(validators);
  5360. this._setAsyncValidators(asyncValidators);
  5361. }
  5362. /** @internal */
  5363. _checkParentType() {
  5364. if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  5365. throw groupParentException();
  5366. }
  5367. }
  5368. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormGroupName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
  5369. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: FormGroupName, isStandalone: false, selector: "[formGroupName]", inputs: { name: ["formGroupName", "name"] }, providers: [formGroupNameProvider], usesInheritance: true, ngImport: i0 });
  5370. }
  5371. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormGroupName, decorators: [{
  5372. type: Directive,
  5373. args: [{
  5374. selector: '[formGroupName]',
  5375. providers: [formGroupNameProvider],
  5376. standalone: false,
  5377. }]
  5378. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  5379. type: Optional
  5380. }, {
  5381. type: Host
  5382. }, {
  5383. type: SkipSelf
  5384. }] }, { type: undefined, decorators: [{
  5385. type: Optional
  5386. }, {
  5387. type: Self
  5388. }, {
  5389. type: Inject,
  5390. args: [NG_VALIDATORS]
  5391. }] }, { type: undefined, decorators: [{
  5392. type: Optional
  5393. }, {
  5394. type: Self
  5395. }, {
  5396. type: Inject,
  5397. args: [NG_ASYNC_VALIDATORS]
  5398. }] }], propDecorators: { name: [{
  5399. type: Input,
  5400. args: ['formGroupName']
  5401. }] } });
  5402. const formArrayNameProvider = {
  5403. provide: ControlContainer,
  5404. useExisting: forwardRef(() => FormArrayName),
  5405. };
  5406. /**
  5407. * @description
  5408. *
  5409. * Syncs a nested `FormArray` to a DOM element.
  5410. *
  5411. * This directive is designed to be used with a parent `FormGroupDirective` (selector:
  5412. * `[formGroup]`).
  5413. *
  5414. * It accepts the string name of the nested `FormArray` you want to link, and
  5415. * will look for a `FormArray` registered with that name in the parent
  5416. * `FormGroup` instance you passed into `FormGroupDirective`.
  5417. *
  5418. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  5419. * @see {@link AbstractControl}
  5420. *
  5421. * @usageNotes
  5422. *
  5423. * ### Example
  5424. *
  5425. * {@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'}
  5426. *
  5427. * @ngModule ReactiveFormsModule
  5428. * @publicApi
  5429. */
  5430. class FormArrayName extends ControlContainer {
  5431. /** @internal */
  5432. _parent;
  5433. /**
  5434. * @description
  5435. * Tracks the name of the `FormArray` bound to the directive. The name corresponds
  5436. * to a key in the parent `FormGroup` or `FormArray`.
  5437. * Accepts a name as a string or a number.
  5438. * The name in the form of a string is useful for individual forms,
  5439. * while the numerical form allows for form arrays to be bound
  5440. * to indices when iterating over arrays in a `FormArray`.
  5441. */
  5442. name = null;
  5443. constructor(parent, validators, asyncValidators) {
  5444. super();
  5445. this._parent = parent;
  5446. this._setValidators(validators);
  5447. this._setAsyncValidators(asyncValidators);
  5448. }
  5449. /**
  5450. * A lifecycle method called when the directive's inputs are initialized. For internal use only.
  5451. * @throws If the directive does not have a valid parent.
  5452. * @nodoc
  5453. */
  5454. ngOnInit() {
  5455. if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  5456. throw arrayParentException();
  5457. }
  5458. this.formDirective.addFormArray(this);
  5459. }
  5460. /**
  5461. * A lifecycle method called before the directive's instance is destroyed. For internal use only.
  5462. * @nodoc
  5463. */
  5464. ngOnDestroy() {
  5465. this.formDirective?.removeFormArray(this);
  5466. }
  5467. /**
  5468. * @description
  5469. * The `FormArray` bound to this directive.
  5470. */
  5471. get control() {
  5472. return this.formDirective.getFormArray(this);
  5473. }
  5474. /**
  5475. * @description
  5476. * The top-level directive for this group if present, otherwise null.
  5477. */
  5478. get formDirective() {
  5479. return this._parent ? this._parent.formDirective : null;
  5480. }
  5481. /**
  5482. * @description
  5483. * Returns an array that represents the path from the top-level form to this control.
  5484. * Each index is the string name of the control on that level.
  5485. */
  5486. get path() {
  5487. return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
  5488. }
  5489. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormArrayName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
  5490. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: FormArrayName, isStandalone: false, selector: "[formArrayName]", inputs: { name: ["formArrayName", "name"] }, providers: [formArrayNameProvider], usesInheritance: true, ngImport: i0 });
  5491. }
  5492. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormArrayName, decorators: [{
  5493. type: Directive,
  5494. args: [{
  5495. selector: '[formArrayName]',
  5496. providers: [formArrayNameProvider],
  5497. standalone: false,
  5498. }]
  5499. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  5500. type: Optional
  5501. }, {
  5502. type: Host
  5503. }, {
  5504. type: SkipSelf
  5505. }] }, { type: undefined, decorators: [{
  5506. type: Optional
  5507. }, {
  5508. type: Self
  5509. }, {
  5510. type: Inject,
  5511. args: [NG_VALIDATORS]
  5512. }] }, { type: undefined, decorators: [{
  5513. type: Optional
  5514. }, {
  5515. type: Self
  5516. }, {
  5517. type: Inject,
  5518. args: [NG_ASYNC_VALIDATORS]
  5519. }] }], propDecorators: { name: [{
  5520. type: Input,
  5521. args: ['formArrayName']
  5522. }] } });
  5523. function hasInvalidParent(parent) {
  5524. return (!(parent instanceof FormGroupName) &&
  5525. !(parent instanceof FormGroupDirective) &&
  5526. !(parent instanceof FormArrayName));
  5527. }
  5528. const controlNameBinding = {
  5529. provide: NgControl,
  5530. useExisting: forwardRef(() => FormControlName),
  5531. };
  5532. /**
  5533. * @description
  5534. * Syncs a `FormControl` in an existing `FormGroup` to a form control
  5535. * element by name.
  5536. *
  5537. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  5538. * @see {@link FormControl}
  5539. * @see {@link AbstractControl}
  5540. *
  5541. * @usageNotes
  5542. *
  5543. * ### Register `FormControl` within a group
  5544. *
  5545. * The following example shows how to register multiple form controls within a form group
  5546. * and set their value.
  5547. *
  5548. * {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
  5549. *
  5550. * To see `formControlName` examples with different form control types, see:
  5551. *
  5552. * * Radio buttons: `RadioControlValueAccessor`
  5553. * * Selects: `SelectControlValueAccessor`
  5554. *
  5555. * ### Use with ngModel is deprecated
  5556. *
  5557. * Support for using the `ngModel` input property and `ngModelChange` event with reactive
  5558. * form directives has been deprecated in Angular v6 and is scheduled for removal in
  5559. * a future version of Angular.
  5560. *
  5561. * @ngModule ReactiveFormsModule
  5562. * @publicApi
  5563. */
  5564. class FormControlName extends NgControl {
  5565. _ngModelWarningConfig;
  5566. _added = false;
  5567. /**
  5568. * Internal reference to the view model value.
  5569. * @internal
  5570. */
  5571. viewModel;
  5572. /**
  5573. * @description
  5574. * Tracks the `FormControl` instance bound to the directive.
  5575. */
  5576. // TODO(issue/24571): remove '!'.
  5577. control;
  5578. /**
  5579. * @description
  5580. * Tracks the name of the `FormControl` bound to the directive. The name corresponds
  5581. * to a key in the parent `FormGroup` or `FormArray`.
  5582. * Accepts a name as a string or a number.
  5583. * The name in the form of a string is useful for individual forms,
  5584. * while the numerical form allows for form controls to be bound
  5585. * to indices when iterating over controls in a `FormArray`.
  5586. */
  5587. name = null;
  5588. /**
  5589. * @description
  5590. * Triggers a warning in dev mode that this input should not be used with reactive forms.
  5591. */
  5592. set isDisabled(isDisabled) {
  5593. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  5594. console.warn(disabledAttrWarning);
  5595. }
  5596. }
  5597. // TODO(kara): remove next 4 properties once deprecation period is over
  5598. /** @deprecated as of v6 */
  5599. model;
  5600. /** @deprecated as of v6 */
  5601. update = new EventEmitter();
  5602. /**
  5603. * @description
  5604. * Static property used to track whether any ngModel warnings have been sent across
  5605. * all instances of FormControlName. Used to support warning config of "once".
  5606. *
  5607. * @internal
  5608. */
  5609. static _ngModelWarningSentOnce = false;
  5610. /**
  5611. * @description
  5612. * Instance property used to track whether an ngModel warning has been sent out for this
  5613. * particular FormControlName instance. Used to support warning config of "always".
  5614. *
  5615. * @internal
  5616. */
  5617. _ngModelWarningSent = false;
  5618. constructor(parent, validators, asyncValidators, valueAccessors, _ngModelWarningConfig) {
  5619. super();
  5620. this._ngModelWarningConfig = _ngModelWarningConfig;
  5621. this._parent = parent;
  5622. this._setValidators(validators);
  5623. this._setAsyncValidators(asyncValidators);
  5624. this.valueAccessor = selectValueAccessor(this, valueAccessors);
  5625. }
  5626. /** @nodoc */
  5627. ngOnChanges(changes) {
  5628. if (!this._added)
  5629. this._setUpControl();
  5630. if (isPropertyUpdated(changes, this.viewModel)) {
  5631. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  5632. _ngModelWarning('formControlName', FormControlName, this, this._ngModelWarningConfig);
  5633. }
  5634. this.viewModel = this.model;
  5635. this.formDirective.updateModel(this, this.model);
  5636. }
  5637. }
  5638. /** @nodoc */
  5639. ngOnDestroy() {
  5640. if (this.formDirective) {
  5641. this.formDirective.removeControl(this);
  5642. }
  5643. }
  5644. /**
  5645. * @description
  5646. * Sets the new value for the view model and emits an `ngModelChange` event.
  5647. *
  5648. * @param newValue The new value for the view model.
  5649. */
  5650. viewToModelUpdate(newValue) {
  5651. this.viewModel = newValue;
  5652. this.update.emit(newValue);
  5653. }
  5654. /**
  5655. * @description
  5656. * Returns an array that represents the path from the top-level form to this control.
  5657. * Each index is the string name of the control on that level.
  5658. */
  5659. get path() {
  5660. return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
  5661. }
  5662. /**
  5663. * @description
  5664. * The top-level directive for this group if present, otherwise null.
  5665. */
  5666. get formDirective() {
  5667. return this._parent ? this._parent.formDirective : null;
  5668. }
  5669. _setUpControl() {
  5670. if (typeof ngDevMode === 'undefined' || ngDevMode) {
  5671. checkParentType(this._parent, this.name);
  5672. }
  5673. this.control = this.formDirective.addControl(this);
  5674. this._added = true;
  5675. }
  5676. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormControlName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  5677. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: FormControlName, isStandalone: false, selector: "[formControlName]", inputs: { name: ["formControlName", "name"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [controlNameBinding], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
  5678. }
  5679. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormControlName, decorators: [{
  5680. type: Directive,
  5681. args: [{
  5682. selector: '[formControlName]',
  5683. providers: [controlNameBinding],
  5684. standalone: false,
  5685. }]
  5686. }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
  5687. type: Optional
  5688. }, {
  5689. type: Host
  5690. }, {
  5691. type: SkipSelf
  5692. }] }, { type: undefined, decorators: [{
  5693. type: Optional
  5694. }, {
  5695. type: Self
  5696. }, {
  5697. type: Inject,
  5698. args: [NG_VALIDATORS]
  5699. }] }, { type: undefined, decorators: [{
  5700. type: Optional
  5701. }, {
  5702. type: Self
  5703. }, {
  5704. type: Inject,
  5705. args: [NG_ASYNC_VALIDATORS]
  5706. }] }, { type: undefined, decorators: [{
  5707. type: Optional
  5708. }, {
  5709. type: Self
  5710. }, {
  5711. type: Inject,
  5712. args: [NG_VALUE_ACCESSOR]
  5713. }] }, { type: undefined, decorators: [{
  5714. type: Optional
  5715. }, {
  5716. type: Inject,
  5717. args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
  5718. }] }], propDecorators: { name: [{
  5719. type: Input,
  5720. args: ['formControlName']
  5721. }], isDisabled: [{
  5722. type: Input,
  5723. args: ['disabled']
  5724. }], model: [{
  5725. type: Input,
  5726. args: ['ngModel']
  5727. }], update: [{
  5728. type: Output,
  5729. args: ['ngModelChange']
  5730. }] } });
  5731. function checkParentType(parent, name) {
  5732. if (!(parent instanceof FormGroupName) && parent instanceof AbstractFormGroupDirective) {
  5733. throw ngModelGroupException();
  5734. }
  5735. else if (!(parent instanceof FormGroupName) &&
  5736. !(parent instanceof FormGroupDirective) &&
  5737. !(parent instanceof FormArrayName)) {
  5738. throw controlParentException(name);
  5739. }
  5740. }
  5741. const SELECT_VALUE_ACCESSOR = {
  5742. provide: NG_VALUE_ACCESSOR,
  5743. useExisting: forwardRef(() => SelectControlValueAccessor),
  5744. multi: true,
  5745. };
  5746. function _buildValueString$1(id, value) {
  5747. if (id == null)
  5748. return `${value}`;
  5749. if (value && typeof value === 'object')
  5750. value = 'Object';
  5751. return `${id}: ${value}`.slice(0, 50);
  5752. }
  5753. function _extractId$1(valueString) {
  5754. return valueString.split(':')[0];
  5755. }
  5756. /**
  5757. * @description
  5758. * The `ControlValueAccessor` for writing select control values and listening to select control
  5759. * changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
  5760. * `NgModel` directives.
  5761. *
  5762. * @usageNotes
  5763. *
  5764. * ### Using select controls in a reactive form
  5765. *
  5766. * The following examples show how to use a select control in a reactive form.
  5767. *
  5768. * {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
  5769. *
  5770. * ### Using select controls in a template-driven form
  5771. *
  5772. * To use a select in a template-driven form, simply add an `ngModel` and a `name`
  5773. * attribute to the main `<select>` tag.
  5774. *
  5775. * {@example forms/ts/selectControl/select_control_example.ts region='Component'}
  5776. *
  5777. * ### Customizing option selection
  5778. *
  5779. * Angular uses object identity to select option. It's possible for the identities of items
  5780. * to change while the data does not. This can happen, for example, if the items are produced
  5781. * from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
  5782. * second response will produce objects with different identities.
  5783. *
  5784. * To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
  5785. * `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
  5786. * If `compareWith` is given, Angular selects option by the return value of the function.
  5787. *
  5788. * ```ts
  5789. * const selectedCountriesControl = new FormControl();
  5790. * ```
  5791. *
  5792. * ```html
  5793. * <select [compareWith]="compareFn" [formControl]="selectedCountriesControl">
  5794. * <option *ngFor="let country of countries" [ngValue]="country">
  5795. * {{country.name}}
  5796. * </option>
  5797. * </select>
  5798. *
  5799. * compareFn(c1: Country, c2: Country): boolean {
  5800. * return c1 && c2 ? c1.id === c2.id : c1 === c2;
  5801. * }
  5802. * ```
  5803. *
  5804. * **Note:** We listen to the 'change' event because 'input' events aren't fired
  5805. * for selects in IE, see:
  5806. * https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event#browser_compatibility
  5807. *
  5808. * @ngModule ReactiveFormsModule
  5809. * @ngModule FormsModule
  5810. * @publicApi
  5811. */
  5812. class SelectControlValueAccessor extends BuiltInControlValueAccessor {
  5813. /** @nodoc */
  5814. value;
  5815. /** @internal */
  5816. _optionMap = new Map();
  5817. /** @internal */
  5818. _idCounter = 0;
  5819. /**
  5820. * @description
  5821. * Tracks the option comparison algorithm for tracking identities when
  5822. * checking for changes.
  5823. */
  5824. set compareWith(fn) {
  5825. if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  5826. throw new _RuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
  5827. }
  5828. this._compareWith = fn;
  5829. }
  5830. _compareWith = Object.is;
  5831. /**
  5832. * Sets the "value" property on the select element.
  5833. * @nodoc
  5834. */
  5835. writeValue(value) {
  5836. this.value = value;
  5837. const id = this._getOptionId(value);
  5838. const valueString = _buildValueString$1(id, value);
  5839. this.setProperty('value', valueString);
  5840. }
  5841. /**
  5842. * Registers a function called when the control value changes.
  5843. * @nodoc
  5844. */
  5845. registerOnChange(fn) {
  5846. this.onChange = (valueString) => {
  5847. this.value = this._getOptionValue(valueString);
  5848. fn(this.value);
  5849. };
  5850. }
  5851. /** @internal */
  5852. _registerOption() {
  5853. return (this._idCounter++).toString();
  5854. }
  5855. /** @internal */
  5856. _getOptionId(value) {
  5857. for (const id of this._optionMap.keys()) {
  5858. if (this._compareWith(this._optionMap.get(id), value))
  5859. return id;
  5860. }
  5861. return null;
  5862. }
  5863. /** @internal */
  5864. _getOptionValue(valueString) {
  5865. const id = _extractId$1(valueString);
  5866. return this._optionMap.has(id) ? this._optionMap.get(id) : valueString;
  5867. }
  5868. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  5869. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: SelectControlValueAccessor, isStandalone: false, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [SELECT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  5870. }
  5871. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectControlValueAccessor, decorators: [{
  5872. type: Directive,
  5873. args: [{
  5874. selector: 'select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]',
  5875. host: { '(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
  5876. providers: [SELECT_VALUE_ACCESSOR],
  5877. standalone: false,
  5878. }]
  5879. }], propDecorators: { compareWith: [{
  5880. type: Input
  5881. }] } });
  5882. /**
  5883. * @description
  5884. * Marks `<option>` as dynamic, so Angular can be notified when options change.
  5885. *
  5886. * @see {@link SelectControlValueAccessor}
  5887. *
  5888. * @ngModule ReactiveFormsModule
  5889. * @ngModule FormsModule
  5890. * @publicApi
  5891. */
  5892. class NgSelectOption {
  5893. _element;
  5894. _renderer;
  5895. _select;
  5896. /**
  5897. * @description
  5898. * ID of the option element
  5899. */
  5900. // TODO(issue/24571): remove '!'.
  5901. id;
  5902. constructor(_element, _renderer, _select) {
  5903. this._element = _element;
  5904. this._renderer = _renderer;
  5905. this._select = _select;
  5906. if (this._select)
  5907. this.id = this._select._registerOption();
  5908. }
  5909. /**
  5910. * @description
  5911. * Tracks the value bound to the option element. Unlike the value binding,
  5912. * ngValue supports binding to objects.
  5913. */
  5914. set ngValue(value) {
  5915. if (this._select == null)
  5916. return;
  5917. this._select._optionMap.set(this.id, value);
  5918. this._setElementValue(_buildValueString$1(this.id, value));
  5919. this._select.writeValue(this._select.value);
  5920. }
  5921. /**
  5922. * @description
  5923. * Tracks simple string values bound to the option element.
  5924. * For objects, use the `ngValue` input binding.
  5925. */
  5926. set value(value) {
  5927. this._setElementValue(value);
  5928. if (this._select)
  5929. this._select.writeValue(this._select.value);
  5930. }
  5931. /** @internal */
  5932. _setElementValue(value) {
  5933. this._renderer.setProperty(this._element.nativeElement, 'value', value);
  5934. }
  5935. /** @nodoc */
  5936. ngOnDestroy() {
  5937. if (this._select) {
  5938. this._select._optionMap.delete(this.id);
  5939. this._select.writeValue(this._select.value);
  5940. }
  5941. }
  5942. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgSelectOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  5943. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: NgSelectOption, isStandalone: false, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 });
  5944. }
  5945. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NgSelectOption, decorators: [{
  5946. type: Directive,
  5947. args: [{
  5948. selector: 'option',
  5949. standalone: false,
  5950. }]
  5951. }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectControlValueAccessor, decorators: [{
  5952. type: Optional
  5953. }, {
  5954. type: Host
  5955. }] }], propDecorators: { ngValue: [{
  5956. type: Input,
  5957. args: ['ngValue']
  5958. }], value: [{
  5959. type: Input,
  5960. args: ['value']
  5961. }] } });
  5962. const SELECT_MULTIPLE_VALUE_ACCESSOR = {
  5963. provide: NG_VALUE_ACCESSOR,
  5964. useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
  5965. multi: true,
  5966. };
  5967. function _buildValueString(id, value) {
  5968. if (id == null)
  5969. return `${value}`;
  5970. if (typeof value === 'string')
  5971. value = `'${value}'`;
  5972. if (value && typeof value === 'object')
  5973. value = 'Object';
  5974. return `${id}: ${value}`.slice(0, 50);
  5975. }
  5976. function _extractId(valueString) {
  5977. return valueString.split(':')[0];
  5978. }
  5979. /**
  5980. * @description
  5981. * The `ControlValueAccessor` for writing multi-select control values and listening to multi-select
  5982. * control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
  5983. * `NgModel` directives.
  5984. *
  5985. * @see {@link SelectControlValueAccessor}
  5986. *
  5987. * @usageNotes
  5988. *
  5989. * ### Using a multi-select control
  5990. *
  5991. * The follow example shows you how to use a multi-select control with a reactive form.
  5992. *
  5993. * ```ts
  5994. * const countryControl = new FormControl();
  5995. * ```
  5996. *
  5997. * ```html
  5998. * <select multiple name="countries" [formControl]="countryControl">
  5999. * <option *ngFor="let country of countries" [ngValue]="country">
  6000. * {{ country.name }}
  6001. * </option>
  6002. * </select>
  6003. * ```
  6004. *
  6005. * ### Customizing option selection
  6006. *
  6007. * To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
  6008. * See the `SelectControlValueAccessor` for usage.
  6009. *
  6010. * @ngModule ReactiveFormsModule
  6011. * @ngModule FormsModule
  6012. * @publicApi
  6013. */
  6014. class SelectMultipleControlValueAccessor extends BuiltInControlValueAccessor {
  6015. /**
  6016. * The current value.
  6017. * @nodoc
  6018. */
  6019. value;
  6020. /** @internal */
  6021. _optionMap = new Map();
  6022. /** @internal */
  6023. _idCounter = 0;
  6024. /**
  6025. * @description
  6026. * Tracks the option comparison algorithm for tracking identities when
  6027. * checking for changes.
  6028. */
  6029. set compareWith(fn) {
  6030. if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
  6031. throw new _RuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
  6032. }
  6033. this._compareWith = fn;
  6034. }
  6035. _compareWith = Object.is;
  6036. /**
  6037. * Sets the "value" property on one or of more of the select's options.
  6038. * @nodoc
  6039. */
  6040. writeValue(value) {
  6041. this.value = value;
  6042. let optionSelectedStateSetter;
  6043. if (Array.isArray(value)) {
  6044. // convert values to ids
  6045. const ids = value.map((v) => this._getOptionId(v));
  6046. optionSelectedStateSetter = (opt, o) => {
  6047. opt._setSelected(ids.indexOf(o.toString()) > -1);
  6048. };
  6049. }
  6050. else {
  6051. optionSelectedStateSetter = (opt, o) => {
  6052. opt._setSelected(false);
  6053. };
  6054. }
  6055. this._optionMap.forEach(optionSelectedStateSetter);
  6056. }
  6057. /**
  6058. * Registers a function called when the control value changes
  6059. * and writes an array of the selected options.
  6060. * @nodoc
  6061. */
  6062. registerOnChange(fn) {
  6063. this.onChange = (element) => {
  6064. const selected = [];
  6065. const selectedOptions = element.selectedOptions;
  6066. if (selectedOptions !== undefined) {
  6067. const options = selectedOptions;
  6068. for (let i = 0; i < options.length; i++) {
  6069. const opt = options[i];
  6070. const val = this._getOptionValue(opt.value);
  6071. selected.push(val);
  6072. }
  6073. }
  6074. // Degrade to use `options` when `selectedOptions` property is not available.
  6075. // Note: the `selectedOptions` is available in all supported browsers, but the Domino lib
  6076. // doesn't have it currently, see https://github.com/fgnass/domino/issues/177.
  6077. else {
  6078. const options = element.options;
  6079. for (let i = 0; i < options.length; i++) {
  6080. const opt = options[i];
  6081. if (opt.selected) {
  6082. const val = this._getOptionValue(opt.value);
  6083. selected.push(val);
  6084. }
  6085. }
  6086. }
  6087. this.value = selected;
  6088. fn(selected);
  6089. };
  6090. }
  6091. /** @internal */
  6092. _registerOption(value) {
  6093. const id = (this._idCounter++).toString();
  6094. this._optionMap.set(id, value);
  6095. return id;
  6096. }
  6097. /** @internal */
  6098. _getOptionId(value) {
  6099. for (const id of this._optionMap.keys()) {
  6100. if (this._compareWith(this._optionMap.get(id)._value, value))
  6101. return id;
  6102. }
  6103. return null;
  6104. }
  6105. /** @internal */
  6106. _getOptionValue(valueString) {
  6107. const id = _extractId(valueString);
  6108. return this._optionMap.has(id) ? this._optionMap.get(id)._value : valueString;
  6109. }
  6110. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectMultipleControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6111. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: SelectMultipleControlValueAccessor, isStandalone: false, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target)", "blur": "onTouched()" } }, providers: [SELECT_MULTIPLE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
  6112. }
  6113. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectMultipleControlValueAccessor, decorators: [{
  6114. type: Directive,
  6115. args: [{
  6116. selector: 'select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]',
  6117. host: { '(change)': 'onChange($event.target)', '(blur)': 'onTouched()' },
  6118. providers: [SELECT_MULTIPLE_VALUE_ACCESSOR],
  6119. standalone: false,
  6120. }]
  6121. }], propDecorators: { compareWith: [{
  6122. type: Input
  6123. }] } });
  6124. /**
  6125. * @description
  6126. * Marks `<option>` as dynamic, so Angular can be notified when options change.
  6127. *
  6128. * @see {@link SelectMultipleControlValueAccessor}
  6129. *
  6130. * @ngModule ReactiveFormsModule
  6131. * @ngModule FormsModule
  6132. * @publicApi
  6133. */
  6134. class ɵNgSelectMultipleOption {
  6135. _element;
  6136. _renderer;
  6137. _select;
  6138. // TODO(issue/24571): remove '!'.
  6139. id;
  6140. /** @internal */
  6141. _value;
  6142. constructor(_element, _renderer, _select) {
  6143. this._element = _element;
  6144. this._renderer = _renderer;
  6145. this._select = _select;
  6146. if (this._select) {
  6147. this.id = this._select._registerOption(this);
  6148. }
  6149. }
  6150. /**
  6151. * @description
  6152. * Tracks the value bound to the option element. Unlike the value binding,
  6153. * ngValue supports binding to objects.
  6154. */
  6155. set ngValue(value) {
  6156. if (this._select == null)
  6157. return;
  6158. this._value = value;
  6159. this._setElementValue(_buildValueString(this.id, value));
  6160. this._select.writeValue(this._select.value);
  6161. }
  6162. /**
  6163. * @description
  6164. * Tracks simple string values bound to the option element.
  6165. * For objects, use the `ngValue` input binding.
  6166. */
  6167. set value(value) {
  6168. if (this._select) {
  6169. this._value = value;
  6170. this._setElementValue(_buildValueString(this.id, value));
  6171. this._select.writeValue(this._select.value);
  6172. }
  6173. else {
  6174. this._setElementValue(value);
  6175. }
  6176. }
  6177. /** @internal */
  6178. _setElementValue(value) {
  6179. this._renderer.setProperty(this._element.nativeElement, 'value', value);
  6180. }
  6181. /** @internal */
  6182. _setSelected(selected) {
  6183. this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
  6184. }
  6185. /** @nodoc */
  6186. ngOnDestroy() {
  6187. if (this._select) {
  6188. this._select._optionMap.delete(this.id);
  6189. this._select.writeValue(this._select.value);
  6190. }
  6191. }
  6192. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵNgSelectMultipleOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectMultipleControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
  6193. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: ɵNgSelectMultipleOption, isStandalone: false, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 });
  6194. }
  6195. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵNgSelectMultipleOption, decorators: [{
  6196. type: Directive,
  6197. args: [{
  6198. selector: 'option',
  6199. standalone: false,
  6200. }]
  6201. }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectMultipleControlValueAccessor, decorators: [{
  6202. type: Optional
  6203. }, {
  6204. type: Host
  6205. }] }], propDecorators: { ngValue: [{
  6206. type: Input,
  6207. args: ['ngValue']
  6208. }], value: [{
  6209. type: Input,
  6210. args: ['value']
  6211. }] } });
  6212. /**
  6213. * Method that updates string to integer if not already a number
  6214. *
  6215. * @param value The value to convert to integer.
  6216. * @returns value of parameter converted to number or integer.
  6217. */
  6218. function toInteger(value) {
  6219. return typeof value === 'number' ? value : parseInt(value, 10);
  6220. }
  6221. /**
  6222. * Method that ensures that provided value is a float (and converts it to float if needed).
  6223. *
  6224. * @param value The value to convert to float.
  6225. * @returns value of parameter converted to number or float.
  6226. */
  6227. function toFloat(value) {
  6228. return typeof value === 'number' ? value : parseFloat(value);
  6229. }
  6230. /**
  6231. * A base class for Validator-based Directives. The class contains common logic shared across such
  6232. * Directives.
  6233. *
  6234. * For internal use only, this class is not intended for use outside of the Forms package.
  6235. */
  6236. class AbstractValidatorDirective {
  6237. _validator = nullValidator;
  6238. _onChange;
  6239. /**
  6240. * A flag that tracks whether this validator is enabled.
  6241. *
  6242. * Marking it `internal` (vs `protected`), so that this flag can be used in host bindings of
  6243. * directive classes that extend this base class.
  6244. * @internal
  6245. */
  6246. _enabled;
  6247. /** @nodoc */
  6248. ngOnChanges(changes) {
  6249. if (this.inputName in changes) {
  6250. const input = this.normalizeInput(changes[this.inputName].currentValue);
  6251. this._enabled = this.enabled(input);
  6252. this._validator = this._enabled ? this.createValidator(input) : nullValidator;
  6253. if (this._onChange) {
  6254. this._onChange();
  6255. }
  6256. }
  6257. }
  6258. /** @nodoc */
  6259. validate(control) {
  6260. return this._validator(control);
  6261. }
  6262. /** @nodoc */
  6263. registerOnValidatorChange(fn) {
  6264. this._onChange = fn;
  6265. }
  6266. /**
  6267. * @description
  6268. * Determines whether this validator should be active or not based on an input.
  6269. * Base class implementation checks whether an input is defined (if the value is different from
  6270. * `null` and `undefined`). Validator classes that extend this base class can override this
  6271. * function with the logic specific to a particular validator directive.
  6272. */
  6273. enabled(input) {
  6274. return input != null /* both `null` and `undefined` */;
  6275. }
  6276. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: AbstractValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  6277. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: AbstractValidatorDirective, isStandalone: true, usesOnChanges: true, ngImport: i0 });
  6278. }
  6279. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: AbstractValidatorDirective, decorators: [{
  6280. type: Directive
  6281. }] });
  6282. /**
  6283. * @description
  6284. * Provider which adds `MaxValidator` to the `NG_VALIDATORS` multi-provider list.
  6285. */
  6286. const MAX_VALIDATOR = {
  6287. provide: NG_VALIDATORS,
  6288. useExisting: forwardRef(() => MaxValidator),
  6289. multi: true,
  6290. };
  6291. /**
  6292. * A directive which installs the {@link MaxValidator} for any `formControlName`,
  6293. * `formControl`, or control with `ngModel` that also has a `max` attribute.
  6294. *
  6295. * @see [Form Validation](guide/forms/form-validation)
  6296. *
  6297. * @usageNotes
  6298. *
  6299. * ### Adding a max validator
  6300. *
  6301. * The following example shows how to add a max validator to an input attached to an
  6302. * ngModel binding.
  6303. *
  6304. * ```html
  6305. * <input type="number" ngModel max="4">
  6306. * ```
  6307. *
  6308. * @ngModule ReactiveFormsModule
  6309. * @ngModule FormsModule
  6310. * @publicApi
  6311. */
  6312. class MaxValidator extends AbstractValidatorDirective {
  6313. /**
  6314. * @description
  6315. * Tracks changes to the max bound to this directive.
  6316. */
  6317. max;
  6318. /** @internal */
  6319. inputName = 'max';
  6320. /** @internal */
  6321. normalizeInput = (input) => toFloat(input);
  6322. /** @internal */
  6323. createValidator = (max) => maxValidator(max);
  6324. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MaxValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6325. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: MaxValidator, isStandalone: false, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: { max: "max" }, host: { properties: { "attr.max": "_enabled ? max : null" } }, providers: [MAX_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6326. }
  6327. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MaxValidator, decorators: [{
  6328. type: Directive,
  6329. args: [{
  6330. selector: 'input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]',
  6331. providers: [MAX_VALIDATOR],
  6332. host: { '[attr.max]': '_enabled ? max : null' },
  6333. standalone: false,
  6334. }]
  6335. }], propDecorators: { max: [{
  6336. type: Input
  6337. }] } });
  6338. /**
  6339. * @description
  6340. * Provider which adds `MinValidator` to the `NG_VALIDATORS` multi-provider list.
  6341. */
  6342. const MIN_VALIDATOR = {
  6343. provide: NG_VALIDATORS,
  6344. useExisting: forwardRef(() => MinValidator),
  6345. multi: true,
  6346. };
  6347. /**
  6348. * A directive which installs the {@link MinValidator} for any `formControlName`,
  6349. * `formControl`, or control with `ngModel` that also has a `min` attribute.
  6350. *
  6351. * @see [Form Validation](guide/forms/form-validation)
  6352. *
  6353. * @usageNotes
  6354. *
  6355. * ### Adding a min validator
  6356. *
  6357. * The following example shows how to add a min validator to an input attached to an
  6358. * ngModel binding.
  6359. *
  6360. * ```html
  6361. * <input type="number" ngModel min="4">
  6362. * ```
  6363. *
  6364. * @ngModule ReactiveFormsModule
  6365. * @ngModule FormsModule
  6366. * @publicApi
  6367. */
  6368. class MinValidator extends AbstractValidatorDirective {
  6369. /**
  6370. * @description
  6371. * Tracks changes to the min bound to this directive.
  6372. */
  6373. min;
  6374. /** @internal */
  6375. inputName = 'min';
  6376. /** @internal */
  6377. normalizeInput = (input) => toFloat(input);
  6378. /** @internal */
  6379. createValidator = (min) => minValidator(min);
  6380. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MinValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6381. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: MinValidator, isStandalone: false, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: { min: "min" }, host: { properties: { "attr.min": "_enabled ? min : null" } }, providers: [MIN_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6382. }
  6383. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MinValidator, decorators: [{
  6384. type: Directive,
  6385. args: [{
  6386. selector: 'input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]',
  6387. providers: [MIN_VALIDATOR],
  6388. host: { '[attr.min]': '_enabled ? min : null' },
  6389. standalone: false,
  6390. }]
  6391. }], propDecorators: { min: [{
  6392. type: Input
  6393. }] } });
  6394. /**
  6395. * @description
  6396. * Provider which adds `RequiredValidator` to the `NG_VALIDATORS` multi-provider list.
  6397. */
  6398. const REQUIRED_VALIDATOR = {
  6399. provide: NG_VALIDATORS,
  6400. useExisting: forwardRef(() => RequiredValidator),
  6401. multi: true,
  6402. };
  6403. /**
  6404. * @description
  6405. * Provider which adds `CheckboxRequiredValidator` to the `NG_VALIDATORS` multi-provider list.
  6406. */
  6407. const CHECKBOX_REQUIRED_VALIDATOR = {
  6408. provide: NG_VALIDATORS,
  6409. useExisting: forwardRef(() => CheckboxRequiredValidator),
  6410. multi: true,
  6411. };
  6412. /**
  6413. * @description
  6414. * A directive that adds the `required` validator to any controls marked with the
  6415. * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6416. *
  6417. * @see [Form Validation](guide/forms/form-validation)
  6418. *
  6419. * @usageNotes
  6420. *
  6421. * ### Adding a required validator using template-driven forms
  6422. *
  6423. * ```html
  6424. * <input name="fullName" ngModel required>
  6425. * ```
  6426. *
  6427. * @ngModule FormsModule
  6428. * @ngModule ReactiveFormsModule
  6429. * @publicApi
  6430. */
  6431. class RequiredValidator extends AbstractValidatorDirective {
  6432. /**
  6433. * @description
  6434. * Tracks changes to the required attribute bound to this directive.
  6435. */
  6436. required;
  6437. /** @internal */
  6438. inputName = 'required';
  6439. /** @internal */
  6440. normalizeInput = booleanAttribute;
  6441. /** @internal */
  6442. createValidator = (input) => requiredValidator;
  6443. /** @nodoc */
  6444. enabled(input) {
  6445. return input;
  6446. }
  6447. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6448. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: RequiredValidator, isStandalone: false, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: { required: "required" }, host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6449. }
  6450. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RequiredValidator, decorators: [{
  6451. type: Directive,
  6452. args: [{
  6453. selector: ':not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]',
  6454. providers: [REQUIRED_VALIDATOR],
  6455. host: { '[attr.required]': '_enabled ? "" : null' },
  6456. standalone: false,
  6457. }]
  6458. }], propDecorators: { required: [{
  6459. type: Input
  6460. }] } });
  6461. /**
  6462. * A Directive that adds the `required` validator to checkbox controls marked with the
  6463. * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6464. *
  6465. * @see [Form Validation](guide/forms/form-validation)
  6466. *
  6467. * @usageNotes
  6468. *
  6469. * ### Adding a required checkbox validator using template-driven forms
  6470. *
  6471. * The following example shows how to add a checkbox required validator to an input attached to an
  6472. * ngModel binding.
  6473. *
  6474. * ```html
  6475. * <input type="checkbox" name="active" ngModel required>
  6476. * ```
  6477. *
  6478. * @publicApi
  6479. * @ngModule FormsModule
  6480. * @ngModule ReactiveFormsModule
  6481. */
  6482. class CheckboxRequiredValidator extends RequiredValidator {
  6483. /** @internal */
  6484. createValidator = (input) => requiredTrueValidator;
  6485. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxRequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6486. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: CheckboxRequiredValidator, isStandalone: false, selector: "input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]", host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [CHECKBOX_REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6487. }
  6488. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxRequiredValidator, decorators: [{
  6489. type: Directive,
  6490. args: [{
  6491. selector: 'input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]',
  6492. providers: [CHECKBOX_REQUIRED_VALIDATOR],
  6493. host: { '[attr.required]': '_enabled ? "" : null' },
  6494. standalone: false,
  6495. }]
  6496. }] });
  6497. /**
  6498. * @description
  6499. * Provider which adds `EmailValidator` to the `NG_VALIDATORS` multi-provider list.
  6500. */
  6501. const EMAIL_VALIDATOR = {
  6502. provide: NG_VALIDATORS,
  6503. useExisting: forwardRef(() => EmailValidator),
  6504. multi: true,
  6505. };
  6506. /**
  6507. * A directive that adds the `email` validator to controls marked with the
  6508. * `email` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6509. *
  6510. * The email validation is based on the WHATWG HTML specification with some enhancements to
  6511. * incorporate more RFC rules. More information can be found on the [Validators.email
  6512. * page](api/forms/Validators#email).
  6513. *
  6514. * @see [Form Validation](guide/forms/form-validation)
  6515. *
  6516. * @usageNotes
  6517. *
  6518. * ### Adding an email validator
  6519. *
  6520. * The following example shows how to add an email validator to an input attached to an ngModel
  6521. * binding.
  6522. *
  6523. * ```html
  6524. * <input type="email" name="email" ngModel email>
  6525. * <input type="email" name="email" ngModel email="true">
  6526. * <input type="email" name="email" ngModel [email]="true">
  6527. * ```
  6528. *
  6529. * @publicApi
  6530. * @ngModule FormsModule
  6531. * @ngModule ReactiveFormsModule
  6532. */
  6533. class EmailValidator extends AbstractValidatorDirective {
  6534. /**
  6535. * @description
  6536. * Tracks changes to the email attribute bound to this directive.
  6537. */
  6538. email;
  6539. /** @internal */
  6540. inputName = 'email';
  6541. /** @internal */
  6542. normalizeInput = booleanAttribute;
  6543. /** @internal */
  6544. createValidator = (input) => emailValidator;
  6545. /** @nodoc */
  6546. enabled(input) {
  6547. return input;
  6548. }
  6549. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EmailValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6550. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: EmailValidator, isStandalone: false, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: { email: "email" }, providers: [EMAIL_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6551. }
  6552. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EmailValidator, decorators: [{
  6553. type: Directive,
  6554. args: [{
  6555. selector: '[email][formControlName],[email][formControl],[email][ngModel]',
  6556. providers: [EMAIL_VALIDATOR],
  6557. standalone: false,
  6558. }]
  6559. }], propDecorators: { email: [{
  6560. type: Input
  6561. }] } });
  6562. /**
  6563. * @description
  6564. * Provider which adds `MinLengthValidator` to the `NG_VALIDATORS` multi-provider list.
  6565. */
  6566. const MIN_LENGTH_VALIDATOR = {
  6567. provide: NG_VALIDATORS,
  6568. useExisting: forwardRef(() => MinLengthValidator),
  6569. multi: true,
  6570. };
  6571. /**
  6572. * A directive that adds minimum length validation to controls marked with the
  6573. * `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6574. *
  6575. * @see [Form Validation](guide/forms/form-validation)
  6576. *
  6577. * @usageNotes
  6578. *
  6579. * ### Adding a minimum length validator
  6580. *
  6581. * The following example shows how to add a minimum length validator to an input attached to an
  6582. * ngModel binding.
  6583. *
  6584. * ```html
  6585. * <input name="firstName" ngModel minlength="4">
  6586. * ```
  6587. *
  6588. * @ngModule ReactiveFormsModule
  6589. * @ngModule FormsModule
  6590. * @publicApi
  6591. */
  6592. class MinLengthValidator extends AbstractValidatorDirective {
  6593. /**
  6594. * @description
  6595. * Tracks changes to the minimum length bound to this directive.
  6596. */
  6597. minlength;
  6598. /** @internal */
  6599. inputName = 'minlength';
  6600. /** @internal */
  6601. normalizeInput = (input) => toInteger(input);
  6602. /** @internal */
  6603. createValidator = (minlength) => minLengthValidator(minlength);
  6604. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MinLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6605. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: MinLengthValidator, isStandalone: false, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: { minlength: "minlength" }, host: { properties: { "attr.minlength": "_enabled ? minlength : null" } }, providers: [MIN_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6606. }
  6607. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MinLengthValidator, decorators: [{
  6608. type: Directive,
  6609. args: [{
  6610. selector: '[minlength][formControlName],[minlength][formControl],[minlength][ngModel]',
  6611. providers: [MIN_LENGTH_VALIDATOR],
  6612. host: { '[attr.minlength]': '_enabled ? minlength : null' },
  6613. standalone: false,
  6614. }]
  6615. }], propDecorators: { minlength: [{
  6616. type: Input
  6617. }] } });
  6618. /**
  6619. * @description
  6620. * Provider which adds `MaxLengthValidator` to the `NG_VALIDATORS` multi-provider list.
  6621. */
  6622. const MAX_LENGTH_VALIDATOR = {
  6623. provide: NG_VALIDATORS,
  6624. useExisting: forwardRef(() => MaxLengthValidator),
  6625. multi: true,
  6626. };
  6627. /**
  6628. * A directive that adds maximum length validation to controls marked with the
  6629. * `maxlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6630. *
  6631. * @see [Form Validation](guide/forms/form-validation)
  6632. *
  6633. * @usageNotes
  6634. *
  6635. * ### Adding a maximum length validator
  6636. *
  6637. * The following example shows how to add a maximum length validator to an input attached to an
  6638. * ngModel binding.
  6639. *
  6640. * ```html
  6641. * <input name="firstName" ngModel maxlength="25">
  6642. * ```
  6643. *
  6644. * @ngModule ReactiveFormsModule
  6645. * @ngModule FormsModule
  6646. * @publicApi
  6647. */
  6648. class MaxLengthValidator extends AbstractValidatorDirective {
  6649. /**
  6650. * @description
  6651. * Tracks changes to the maximum length bound to this directive.
  6652. */
  6653. maxlength;
  6654. /** @internal */
  6655. inputName = 'maxlength';
  6656. /** @internal */
  6657. normalizeInput = (input) => toInteger(input);
  6658. /** @internal */
  6659. createValidator = (maxlength) => maxLengthValidator(maxlength);
  6660. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MaxLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6661. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: MaxLengthValidator, isStandalone: false, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: { maxlength: "maxlength" }, host: { properties: { "attr.maxlength": "_enabled ? maxlength : null" } }, providers: [MAX_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6662. }
  6663. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MaxLengthValidator, decorators: [{
  6664. type: Directive,
  6665. args: [{
  6666. selector: '[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]',
  6667. providers: [MAX_LENGTH_VALIDATOR],
  6668. host: { '[attr.maxlength]': '_enabled ? maxlength : null' },
  6669. standalone: false,
  6670. }]
  6671. }], propDecorators: { maxlength: [{
  6672. type: Input
  6673. }] } });
  6674. /**
  6675. * @description
  6676. * Provider which adds `PatternValidator` to the `NG_VALIDATORS` multi-provider list.
  6677. */
  6678. const PATTERN_VALIDATOR = {
  6679. provide: NG_VALIDATORS,
  6680. useExisting: forwardRef(() => PatternValidator),
  6681. multi: true,
  6682. };
  6683. /**
  6684. * @description
  6685. * A directive that adds regex pattern validation to controls marked with the
  6686. * `pattern` attribute. The regex must match the entire control value.
  6687. * The directive is provided with the `NG_VALIDATORS` multi-provider list.
  6688. *
  6689. * @see [Form Validation](guide/forms/form-validation)
  6690. *
  6691. * @usageNotes
  6692. *
  6693. * ### Adding a pattern validator
  6694. *
  6695. * The following example shows how to add a pattern validator to an input attached to an
  6696. * ngModel binding.
  6697. *
  6698. * ```html
  6699. * <input name="firstName" ngModel pattern="[a-zA-Z ]*">
  6700. * ```
  6701. *
  6702. * @ngModule ReactiveFormsModule
  6703. * @ngModule FormsModule
  6704. * @publicApi
  6705. */
  6706. class PatternValidator extends AbstractValidatorDirective {
  6707. /**
  6708. * @description
  6709. * Tracks changes to the pattern bound to this directive.
  6710. */
  6711. pattern; // This input is always defined, since the name matches selector.
  6712. /** @internal */
  6713. inputName = 'pattern';
  6714. /** @internal */
  6715. normalizeInput = (input) => input;
  6716. /** @internal */
  6717. createValidator = (input) => patternValidator(input);
  6718. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: PatternValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  6719. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: PatternValidator, isStandalone: false, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: { pattern: "pattern" }, host: { properties: { "attr.pattern": "_enabled ? pattern : null" } }, providers: [PATTERN_VALIDATOR], usesInheritance: true, ngImport: i0 });
  6720. }
  6721. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: PatternValidator, decorators: [{
  6722. type: Directive,
  6723. args: [{
  6724. selector: '[pattern][formControlName],[pattern][formControl],[pattern][ngModel]',
  6725. providers: [PATTERN_VALIDATOR],
  6726. host: { '[attr.pattern]': '_enabled ? pattern : null' },
  6727. standalone: false,
  6728. }]
  6729. }], propDecorators: { pattern: [{
  6730. type: Input
  6731. }] } });
  6732. const SHARED_FORM_DIRECTIVES = [
  6733. ɵNgNoValidate,
  6734. NgSelectOption,
  6735. ɵNgSelectMultipleOption,
  6736. DefaultValueAccessor,
  6737. NumberValueAccessor,
  6738. RangeValueAccessor,
  6739. CheckboxControlValueAccessor,
  6740. SelectControlValueAccessor,
  6741. SelectMultipleControlValueAccessor,
  6742. RadioControlValueAccessor,
  6743. NgControlStatus,
  6744. NgControlStatusGroup,
  6745. RequiredValidator,
  6746. MinLengthValidator,
  6747. MaxLengthValidator,
  6748. PatternValidator,
  6749. CheckboxRequiredValidator,
  6750. EmailValidator,
  6751. MinValidator,
  6752. MaxValidator,
  6753. ];
  6754. const TEMPLATE_DRIVEN_DIRECTIVES = [NgModel, NgModelGroup, NgForm];
  6755. const REACTIVE_DRIVEN_DIRECTIVES = [
  6756. FormControlDirective,
  6757. FormGroupDirective,
  6758. FormControlName,
  6759. FormGroupName,
  6760. FormArrayName,
  6761. ];
  6762. /**
  6763. * Internal module used for sharing directives between FormsModule and ReactiveFormsModule
  6764. */
  6765. class ɵInternalFormsSharedModule {
  6766. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵInternalFormsSharedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  6767. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: ɵInternalFormsSharedModule, declarations: [ɵNgNoValidate,
  6768. NgSelectOption,
  6769. ɵNgSelectMultipleOption,
  6770. DefaultValueAccessor,
  6771. NumberValueAccessor,
  6772. RangeValueAccessor,
  6773. CheckboxControlValueAccessor,
  6774. SelectControlValueAccessor,
  6775. SelectMultipleControlValueAccessor,
  6776. RadioControlValueAccessor,
  6777. NgControlStatus,
  6778. NgControlStatusGroup,
  6779. RequiredValidator,
  6780. MinLengthValidator,
  6781. MaxLengthValidator,
  6782. PatternValidator,
  6783. CheckboxRequiredValidator,
  6784. EmailValidator,
  6785. MinValidator,
  6786. MaxValidator], exports: [ɵNgNoValidate,
  6787. NgSelectOption,
  6788. ɵNgSelectMultipleOption,
  6789. DefaultValueAccessor,
  6790. NumberValueAccessor,
  6791. RangeValueAccessor,
  6792. CheckboxControlValueAccessor,
  6793. SelectControlValueAccessor,
  6794. SelectMultipleControlValueAccessor,
  6795. RadioControlValueAccessor,
  6796. NgControlStatus,
  6797. NgControlStatusGroup,
  6798. RequiredValidator,
  6799. MinLengthValidator,
  6800. MaxLengthValidator,
  6801. PatternValidator,
  6802. CheckboxRequiredValidator,
  6803. EmailValidator,
  6804. MinValidator,
  6805. MaxValidator] });
  6806. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵInternalFormsSharedModule });
  6807. }
  6808. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ɵInternalFormsSharedModule, decorators: [{
  6809. type: NgModule,
  6810. args: [{
  6811. declarations: SHARED_FORM_DIRECTIVES,
  6812. exports: SHARED_FORM_DIRECTIVES,
  6813. }]
  6814. }] });
  6815. /**
  6816. * Tracks the value and validity state of an array of `FormControl`,
  6817. * `FormGroup` or `FormArray` instances.
  6818. *
  6819. * A `FormArray` aggregates the values of each child `FormControl` into an array.
  6820. * It calculates its status by reducing the status values of its children. For example, if one of
  6821. * the controls in a `FormArray` is invalid, the entire array becomes invalid.
  6822. *
  6823. * `FormArray` accepts one generic argument, which is the type of the controls inside.
  6824. * If you need a heterogenous array, use {@link UntypedFormArray}.
  6825. *
  6826. * `FormArray` is one of the four fundamental building blocks used to define forms in Angular,
  6827. * along with `FormControl`, `FormGroup`, and `FormRecord`.
  6828. *
  6829. * @usageNotes
  6830. *
  6831. * ### Create an array of form controls
  6832. *
  6833. * ```ts
  6834. * const arr = new FormArray([
  6835. * new FormControl('Nancy', Validators.minLength(2)),
  6836. * new FormControl('Drew'),
  6837. * ]);
  6838. *
  6839. * console.log(arr.value); // ['Nancy', 'Drew']
  6840. * console.log(arr.status); // 'VALID'
  6841. * ```
  6842. *
  6843. * ### Create a form array with array-level validators
  6844. *
  6845. * You include array-level validators and async validators. These come in handy
  6846. * when you want to perform validation that considers the value of more than one child
  6847. * control.
  6848. *
  6849. * The two types of validators are passed in separately as the second and third arg
  6850. * respectively, or together as part of an options object.
  6851. *
  6852. * ```ts
  6853. * const arr = new FormArray([
  6854. * new FormControl('Nancy'),
  6855. * new FormControl('Drew')
  6856. * ], {validators: myValidator, asyncValidators: myAsyncValidator});
  6857. * ```
  6858. *
  6859. * ### Set the updateOn property for all controls in a form array
  6860. *
  6861. * The options object is used to set a default value for each child
  6862. * control's `updateOn` property. If you set `updateOn` to `'blur'` at the
  6863. * array level, all child controls default to 'blur', unless the child
  6864. * has explicitly specified a different `updateOn` value.
  6865. *
  6866. * ```ts
  6867. * const arr = new FormArray([
  6868. * new FormControl()
  6869. * ], {updateOn: 'blur'});
  6870. * ```
  6871. *
  6872. * ### Adding or removing controls from a form array
  6873. *
  6874. * To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
  6875. * in `FormArray` itself. These methods ensure the controls are properly tracked in the
  6876. * form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
  6877. * the `FormArray` directly, as that result in strange and unexpected behavior such
  6878. * as broken change detection.
  6879. *
  6880. * @publicApi
  6881. */
  6882. class FormArray extends AbstractControl {
  6883. /**
  6884. * Creates a new `FormArray` instance.
  6885. *
  6886. * @param controls An array of child controls. Each child control is given an index
  6887. * where it is registered.
  6888. *
  6889. * @param validatorOrOpts A synchronous validator function, or an array of
  6890. * such functions, or an `AbstractControlOptions` object that contains validation functions
  6891. * and a validation trigger.
  6892. *
  6893. * @param asyncValidator A single async validator or array of async validator functions
  6894. *
  6895. */
  6896. constructor(controls, validatorOrOpts, asyncValidator) {
  6897. super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
  6898. this.controls = controls;
  6899. this._initObservables();
  6900. this._setUpdateStrategy(validatorOrOpts);
  6901. this._setUpControls();
  6902. this.updateValueAndValidity({
  6903. onlySelf: true,
  6904. // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
  6905. // `VALID` or `INVALID`.
  6906. // The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
  6907. // to `true` to allow that during the control creation process.
  6908. emitEvent: !!this.asyncValidator,
  6909. });
  6910. }
  6911. controls;
  6912. /**
  6913. * Get the `AbstractControl` at the given `index` in the array.
  6914. *
  6915. * @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
  6916. * around from the back, and if index is greatly negative (less than `-length`), the result is
  6917. * undefined. This behavior is the same as `Array.at(index)`.
  6918. */
  6919. at(index) {
  6920. return this.controls[this._adjustIndex(index)];
  6921. }
  6922. /**
  6923. * Insert a new `AbstractControl` at the end of the array.
  6924. *
  6925. * @param control Form control to be inserted
  6926. * @param options Specifies whether this FormArray instance should emit events after a new
  6927. * control is added.
  6928. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  6929. * `valueChanges` observables emit events with the latest status and value when the control is
  6930. * inserted. When false, no events are emitted.
  6931. */
  6932. push(control, options = {}) {
  6933. this.controls.push(control);
  6934. this._registerControl(control);
  6935. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  6936. this._onCollectionChange();
  6937. }
  6938. /**
  6939. * Insert a new `AbstractControl` at the given `index` in the array.
  6940. *
  6941. * @param index Index in the array to insert the control. If `index` is negative, wraps around
  6942. * from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
  6943. * This behavior is the same as `Array.splice(index, 0, control)`.
  6944. * @param control Form control to be inserted
  6945. * @param options Specifies whether this FormArray instance should emit events after a new
  6946. * control is inserted.
  6947. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  6948. * `valueChanges` observables emit events with the latest status and value when the control is
  6949. * inserted. When false, no events are emitted.
  6950. */
  6951. insert(index, control, options = {}) {
  6952. this.controls.splice(index, 0, control);
  6953. this._registerControl(control);
  6954. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  6955. }
  6956. /**
  6957. * Remove the control at the given `index` in the array.
  6958. *
  6959. * @param index Index in the array to remove the control. If `index` is negative, wraps around
  6960. * from the back. If `index` is greatly negative (less than `-length`), removes the first
  6961. * element. This behavior is the same as `Array.splice(index, 1)`.
  6962. * @param options Specifies whether this FormArray instance should emit events after a
  6963. * control is removed.
  6964. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  6965. * `valueChanges` observables emit events with the latest status and value when the control is
  6966. * removed. When false, no events are emitted.
  6967. */
  6968. removeAt(index, options = {}) {
  6969. // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
  6970. let adjustedIndex = this._adjustIndex(index);
  6971. if (adjustedIndex < 0)
  6972. adjustedIndex = 0;
  6973. if (this.controls[adjustedIndex])
  6974. this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
  6975. this.controls.splice(adjustedIndex, 1);
  6976. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  6977. }
  6978. /**
  6979. * Replace an existing control.
  6980. *
  6981. * @param index Index in the array to replace the control. If `index` is negative, wraps around
  6982. * from the back. If `index` is greatly negative (less than `-length`), replaces the first
  6983. * element. This behavior is the same as `Array.splice(index, 1, control)`.
  6984. * @param control The `AbstractControl` control to replace the existing control
  6985. * @param options Specifies whether this FormArray instance should emit events after an
  6986. * existing control is replaced with a new one.
  6987. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  6988. * `valueChanges` observables emit events with the latest status and value when the control is
  6989. * replaced with a new one. When false, no events are emitted.
  6990. */
  6991. setControl(index, control, options = {}) {
  6992. // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
  6993. let adjustedIndex = this._adjustIndex(index);
  6994. if (adjustedIndex < 0)
  6995. adjustedIndex = 0;
  6996. if (this.controls[adjustedIndex])
  6997. this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
  6998. this.controls.splice(adjustedIndex, 1);
  6999. if (control) {
  7000. this.controls.splice(adjustedIndex, 0, control);
  7001. this._registerControl(control);
  7002. }
  7003. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  7004. this._onCollectionChange();
  7005. }
  7006. /**
  7007. * Length of the control array.
  7008. */
  7009. get length() {
  7010. return this.controls.length;
  7011. }
  7012. /**
  7013. * Sets the value of the `FormArray`. It accepts an array that matches
  7014. * the structure of the control.
  7015. *
  7016. * This method performs strict checks, and throws an error if you try
  7017. * to set the value of a control that doesn't exist or if you exclude the
  7018. * value of a control.
  7019. *
  7020. * @usageNotes
  7021. * ### Set the values for the controls in the form array
  7022. *
  7023. * ```ts
  7024. * const arr = new FormArray([
  7025. * new FormControl(),
  7026. * new FormControl()
  7027. * ]);
  7028. * console.log(arr.value); // [null, null]
  7029. *
  7030. * arr.setValue(['Nancy', 'Drew']);
  7031. * console.log(arr.value); // ['Nancy', 'Drew']
  7032. * ```
  7033. *
  7034. * @param value Array of values for the controls
  7035. * @param options Configure options that determine how the control propagates changes and
  7036. * emits events after the value changes
  7037. *
  7038. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
  7039. * is false.
  7040. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  7041. * `valueChanges`
  7042. * observables emit events with the latest status and value when the control value is updated.
  7043. * When false, no events are emitted.
  7044. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
  7045. * updateValueAndValidity} method.
  7046. */
  7047. setValue(value, options = {}) {
  7048. assertAllValuesPresent(this, false, value);
  7049. value.forEach((newValue, index) => {
  7050. assertControlPresent(this, false, index);
  7051. this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
  7052. });
  7053. this.updateValueAndValidity(options);
  7054. }
  7055. /**
  7056. * Patches the value of the `FormArray`. It accepts an array that matches the
  7057. * structure of the control, and does its best to match the values to the correct
  7058. * controls in the group.
  7059. *
  7060. * It accepts both super-sets and sub-sets of the array without throwing an error.
  7061. *
  7062. * @usageNotes
  7063. * ### Patch the values for controls in a form array
  7064. *
  7065. * ```ts
  7066. * const arr = new FormArray([
  7067. * new FormControl(),
  7068. * new FormControl()
  7069. * ]);
  7070. * console.log(arr.value); // [null, null]
  7071. *
  7072. * arr.patchValue(['Nancy']);
  7073. * console.log(arr.value); // ['Nancy', null]
  7074. * ```
  7075. *
  7076. * @param value Array of latest values for the controls
  7077. * @param options Configure options that determine how the control propagates changes and
  7078. * emits events after the value changes
  7079. *
  7080. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
  7081. * is false.
  7082. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  7083. * `valueChanges` observables emit events with the latest status and value when the control
  7084. * value is updated. When false, no events are emitted. The configuration options are passed to
  7085. * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
  7086. */
  7087. patchValue(value, options = {}) {
  7088. // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
  7089. // `patchValue` can be called recursively and inner data structures might have these values,
  7090. // so we just ignore such cases when a field containing FormArray instance receives `null` or
  7091. // `undefined` as a value.
  7092. if (value == null /* both `null` and `undefined` */)
  7093. return;
  7094. value.forEach((newValue, index) => {
  7095. if (this.at(index)) {
  7096. this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
  7097. }
  7098. });
  7099. this.updateValueAndValidity(options);
  7100. }
  7101. /**
  7102. * Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
  7103. * value of all descendants to null or null maps.
  7104. *
  7105. * You reset to a specific form state by passing in an array of states
  7106. * that matches the structure of the control. The state is a standalone value
  7107. * or a form state object with both a value and a disabled status.
  7108. *
  7109. * @usageNotes
  7110. * ### Reset the values in a form array
  7111. *
  7112. * ```ts
  7113. * const arr = new FormArray([
  7114. * new FormControl(),
  7115. * new FormControl()
  7116. * ]);
  7117. * arr.reset(['name', 'last name']);
  7118. *
  7119. * console.log(arr.value); // ['name', 'last name']
  7120. * ```
  7121. *
  7122. * ### Reset the values in a form array and the disabled status for the first control
  7123. *
  7124. * ```ts
  7125. * arr.reset([
  7126. * {value: 'name', disabled: true},
  7127. * 'last'
  7128. * ]);
  7129. *
  7130. * console.log(arr.value); // ['last']
  7131. * console.log(arr.at(0).status); // 'DISABLED'
  7132. * ```
  7133. *
  7134. * @param value Array of values for the controls
  7135. * @param options Configure options that determine how the control propagates changes and
  7136. * emits events after the value changes
  7137. *
  7138. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
  7139. * is false.
  7140. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  7141. * `valueChanges`
  7142. * observables emit events with the latest status and value when the control is reset.
  7143. * When false, no events are emitted.
  7144. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
  7145. * updateValueAndValidity} method.
  7146. */
  7147. reset(value = [], options = {}) {
  7148. this._forEachChild((control, index) => {
  7149. control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
  7150. });
  7151. this._updatePristine(options, this);
  7152. this._updateTouched(options, this);
  7153. this.updateValueAndValidity(options);
  7154. }
  7155. /**
  7156. * The aggregate value of the array, including any disabled controls.
  7157. *
  7158. * Reports all values regardless of disabled status.
  7159. */
  7160. getRawValue() {
  7161. return this.controls.map((control) => control.getRawValue());
  7162. }
  7163. /**
  7164. * Remove all controls in the `FormArray`.
  7165. *
  7166. * @param options Specifies whether this FormArray instance should emit events after all
  7167. * controls are removed.
  7168. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
  7169. * `valueChanges` observables emit events with the latest status and value when all controls
  7170. * in this FormArray instance are removed. When false, no events are emitted.
  7171. *
  7172. * @usageNotes
  7173. * ### Remove all elements from a FormArray
  7174. *
  7175. * ```ts
  7176. * const arr = new FormArray([
  7177. * new FormControl(),
  7178. * new FormControl()
  7179. * ]);
  7180. * console.log(arr.length); // 2
  7181. *
  7182. * arr.clear();
  7183. * console.log(arr.length); // 0
  7184. * ```
  7185. *
  7186. * It's a simpler and more efficient alternative to removing all elements one by one:
  7187. *
  7188. * ```ts
  7189. * const arr = new FormArray([
  7190. * new FormControl(),
  7191. * new FormControl()
  7192. * ]);
  7193. *
  7194. * while (arr.length) {
  7195. * arr.removeAt(0);
  7196. * }
  7197. * ```
  7198. */
  7199. clear(options = {}) {
  7200. if (this.controls.length < 1)
  7201. return;
  7202. this._forEachChild((control) => control._registerOnCollectionChange(() => { }));
  7203. this.controls.splice(0);
  7204. this.updateValueAndValidity({ emitEvent: options.emitEvent });
  7205. }
  7206. /**
  7207. * Adjusts a negative index by summing it with the length of the array. For very negative
  7208. * indices, the result may remain negative.
  7209. * @internal
  7210. */
  7211. _adjustIndex(index) {
  7212. return index < 0 ? index + this.length : index;
  7213. }
  7214. /** @internal */
  7215. _syncPendingControls() {
  7216. let subtreeUpdated = this.controls.reduce((updated, child) => {
  7217. return child._syncPendingControls() ? true : updated;
  7218. }, false);
  7219. if (subtreeUpdated)
  7220. this.updateValueAndValidity({ onlySelf: true });
  7221. return subtreeUpdated;
  7222. }
  7223. /** @internal */
  7224. _forEachChild(cb) {
  7225. this.controls.forEach((control, index) => {
  7226. cb(control, index);
  7227. });
  7228. }
  7229. /** @internal */
  7230. _updateValue() {
  7231. this.value = this.controls
  7232. .filter((control) => control.enabled || this.disabled)
  7233. .map((control) => control.value);
  7234. }
  7235. /** @internal */
  7236. _anyControls(condition) {
  7237. return this.controls.some((control) => control.enabled && condition(control));
  7238. }
  7239. /** @internal */
  7240. _setUpControls() {
  7241. this._forEachChild((control) => this._registerControl(control));
  7242. }
  7243. /** @internal */
  7244. _allControlsDisabled() {
  7245. for (const control of this.controls) {
  7246. if (control.enabled)
  7247. return false;
  7248. }
  7249. return this.controls.length > 0 || this.disabled;
  7250. }
  7251. _registerControl(control) {
  7252. control.setParent(this);
  7253. control._registerOnCollectionChange(this._onCollectionChange);
  7254. }
  7255. /** @internal */
  7256. _find(name) {
  7257. return this.at(name) ?? null;
  7258. }
  7259. }
  7260. const UntypedFormArray = FormArray;
  7261. /**
  7262. * @description
  7263. * Asserts that the given control is an instance of `FormArray`
  7264. *
  7265. * @publicApi
  7266. */
  7267. const isFormArray = (control) => control instanceof FormArray;
  7268. function isAbstractControlOptions(options) {
  7269. return (!!options &&
  7270. (options.asyncValidators !== undefined ||
  7271. options.validators !== undefined ||
  7272. options.updateOn !== undefined));
  7273. }
  7274. /**
  7275. * @description
  7276. * Creates an `AbstractControl` from a user-specified configuration.
  7277. *
  7278. * The `FormBuilder` provides syntactic sugar that shortens creating instances of a
  7279. * `FormControl`, `FormGroup`, or `FormArray`. It reduces the amount of boilerplate needed to
  7280. * build complex forms.
  7281. *
  7282. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  7283. *
  7284. * @publicApi
  7285. */
  7286. class FormBuilder {
  7287. useNonNullable = false;
  7288. /**
  7289. * @description
  7290. * Returns a FormBuilder in which automatically constructed `FormControl` elements
  7291. * have `{nonNullable: true}` and are non-nullable.
  7292. *
  7293. * **Constructing non-nullable controls**
  7294. *
  7295. * When constructing a control, it will be non-nullable, and will reset to its initial value.
  7296. *
  7297. * ```ts
  7298. * let nnfb = new FormBuilder().nonNullable;
  7299. * let name = nnfb.control('Alex'); // FormControl<string>
  7300. * name.reset();
  7301. * console.log(name); // 'Alex'
  7302. * ```
  7303. *
  7304. * **Constructing non-nullable groups or arrays**
  7305. *
  7306. * When constructing a group or array, all automatically created inner controls will be
  7307. * non-nullable, and will reset to their initial values.
  7308. *
  7309. * ```ts
  7310. * let nnfb = new FormBuilder().nonNullable;
  7311. * let name = nnfb.group({who: 'Alex'}); // FormGroup<{who: FormControl<string>}>
  7312. * name.reset();
  7313. * console.log(name); // {who: 'Alex'}
  7314. * ```
  7315. * **Constructing *nullable* fields on groups or arrays**
  7316. *
  7317. * It is still possible to have a nullable field. In particular, any `FormControl` which is
  7318. * *already* constructed will not be altered. For example:
  7319. *
  7320. * ```ts
  7321. * let nnfb = new FormBuilder().nonNullable;
  7322. * // FormGroup<{who: FormControl<string|null>}>
  7323. * let name = nnfb.group({who: new FormControl('Alex')});
  7324. * name.reset(); console.log(name); // {who: null}
  7325. * ```
  7326. *
  7327. * Because the inner control is constructed explicitly by the caller, the builder has
  7328. * no control over how it is created, and cannot exclude the `null`.
  7329. */
  7330. get nonNullable() {
  7331. const nnfb = new FormBuilder();
  7332. nnfb.useNonNullable = true;
  7333. return nnfb;
  7334. }
  7335. group(controls, options = null) {
  7336. const reducedControls = this._reduceControls(controls);
  7337. let newOptions = {};
  7338. if (isAbstractControlOptions(options)) {
  7339. // `options` are `AbstractControlOptions`
  7340. newOptions = options;
  7341. }
  7342. else if (options !== null) {
  7343. // `options` are legacy form group options
  7344. newOptions.validators = options.validator;
  7345. newOptions.asyncValidators = options.asyncValidator;
  7346. }
  7347. return new FormGroup(reducedControls, newOptions);
  7348. }
  7349. /**
  7350. * @description
  7351. * Constructs a new `FormRecord` instance. Accepts a single generic argument, which is an object
  7352. * containing all the keys and corresponding inner control types.
  7353. *
  7354. * @param controls A collection of child controls. The key for each child is the name
  7355. * under which it is registered.
  7356. *
  7357. * @param options Configuration options object for the `FormRecord`. The object should have the
  7358. * `AbstractControlOptions` type and might contain the following fields:
  7359. * * `validators`: A synchronous validator function, or an array of validator functions.
  7360. * * `asyncValidators`: A single async validator or array of async validator functions.
  7361. * * `updateOn`: The event upon which the control should be updated (options: 'change' | 'blur'
  7362. * | submit').
  7363. */
  7364. record(controls, options = null) {
  7365. const reducedControls = this._reduceControls(controls);
  7366. // Cast to `any` because the inferred types are not as specific as Element.
  7367. return new FormRecord(reducedControls, options);
  7368. }
  7369. /**
  7370. * @description
  7371. * Constructs a new `FormControl` with the given state, validators and options. Sets
  7372. * `{nonNullable: true}` in the options to get a non-nullable control. Otherwise, the
  7373. * control will be nullable. Accepts a single generic argument, which is the type of the
  7374. * control's value.
  7375. *
  7376. * @param formState Initializes the control with an initial state value, or
  7377. * with an object that contains both a value and a disabled status.
  7378. *
  7379. * @param validatorOrOpts A synchronous validator function, or an array of
  7380. * such functions, or a `FormControlOptions` object that contains
  7381. * validation functions and a validation trigger.
  7382. *
  7383. * @param asyncValidator A single async validator or array of async validator
  7384. * functions.
  7385. *
  7386. * @usageNotes
  7387. *
  7388. * ### Initialize a control as disabled
  7389. *
  7390. * The following example returns a control with an initial value in a disabled state.
  7391. *
  7392. * {@example forms/ts/formBuilder/form_builder_example.ts region='disabled-control'}
  7393. */
  7394. control(formState, validatorOrOpts, asyncValidator) {
  7395. let newOptions = {};
  7396. if (!this.useNonNullable) {
  7397. return new FormControl(formState, validatorOrOpts, asyncValidator);
  7398. }
  7399. if (isAbstractControlOptions(validatorOrOpts)) {
  7400. // If the second argument is options, then they are copied.
  7401. newOptions = validatorOrOpts;
  7402. }
  7403. else {
  7404. // If the other arguments are validators, they are copied into an options object.
  7405. newOptions.validators = validatorOrOpts;
  7406. newOptions.asyncValidators = asyncValidator;
  7407. }
  7408. return new FormControl(formState, { ...newOptions, nonNullable: true });
  7409. }
  7410. /**
  7411. * Constructs a new `FormArray` from the given array of configurations,
  7412. * validators and options. Accepts a single generic argument, which is the type of each control
  7413. * inside the array.
  7414. *
  7415. * @param controls An array of child controls or control configs. Each child control is given an
  7416. * index when it is registered.
  7417. *
  7418. * @param validatorOrOpts A synchronous validator function, or an array of such functions, or an
  7419. * `AbstractControlOptions` object that contains
  7420. * validation functions and a validation trigger.
  7421. *
  7422. * @param asyncValidator A single async validator or array of async validator functions.
  7423. */
  7424. array(controls, validatorOrOpts, asyncValidator) {
  7425. const createdControls = controls.map((c) => this._createControl(c));
  7426. // Cast to `any` because the inferred types are not as specific as Element.
  7427. return new FormArray(createdControls, validatorOrOpts, asyncValidator);
  7428. }
  7429. /** @internal */
  7430. _reduceControls(controls) {
  7431. const createdControls = {};
  7432. Object.keys(controls).forEach((controlName) => {
  7433. createdControls[controlName] = this._createControl(controls[controlName]);
  7434. });
  7435. return createdControls;
  7436. }
  7437. /** @internal */
  7438. _createControl(controls) {
  7439. if (controls instanceof FormControl) {
  7440. return controls;
  7441. }
  7442. else if (controls instanceof AbstractControl) {
  7443. // A control; just return it
  7444. return controls;
  7445. }
  7446. else if (Array.isArray(controls)) {
  7447. // ControlConfig Tuple
  7448. const value = controls[0];
  7449. const validator = controls.length > 1 ? controls[1] : null;
  7450. const asyncValidator = controls.length > 2 ? controls[2] : null;
  7451. return this.control(value, validator, asyncValidator);
  7452. }
  7453. else {
  7454. // T or FormControlState<T>
  7455. return this.control(controls);
  7456. }
  7457. }
  7458. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
  7459. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormBuilder, providedIn: 'root' });
  7460. }
  7461. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormBuilder, decorators: [{
  7462. type: Injectable,
  7463. args: [{ providedIn: 'root' }]
  7464. }] });
  7465. /**
  7466. * @description
  7467. * `NonNullableFormBuilder` is similar to {@link FormBuilder}, but automatically constructed
  7468. * {@link FormControl} elements have `{nonNullable: true}` and are non-nullable.
  7469. *
  7470. * @publicApi
  7471. */
  7472. class NonNullableFormBuilder {
  7473. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NonNullableFormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
  7474. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NonNullableFormBuilder, providedIn: 'root', useFactory: () => inject(FormBuilder).nonNullable });
  7475. }
  7476. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NonNullableFormBuilder, decorators: [{
  7477. type: Injectable,
  7478. args: [{
  7479. providedIn: 'root',
  7480. useFactory: () => inject(FormBuilder).nonNullable,
  7481. }]
  7482. }] });
  7483. /**
  7484. * UntypedFormBuilder is the same as `FormBuilder`, but it provides untyped controls.
  7485. */
  7486. class UntypedFormBuilder extends FormBuilder {
  7487. group(controlsConfig, options = null) {
  7488. return super.group(controlsConfig, options);
  7489. }
  7490. /**
  7491. * Like `FormBuilder#control`, except the resulting control is untyped.
  7492. */
  7493. control(formState, validatorOrOpts, asyncValidator) {
  7494. return super.control(formState, validatorOrOpts, asyncValidator);
  7495. }
  7496. /**
  7497. * Like `FormBuilder#array`, except the resulting array is untyped.
  7498. */
  7499. array(controlsConfig, validatorOrOpts, asyncValidator) {
  7500. return super.array(controlsConfig, validatorOrOpts, asyncValidator);
  7501. }
  7502. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UntypedFormBuilder, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
  7503. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UntypedFormBuilder, providedIn: 'root' });
  7504. }
  7505. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UntypedFormBuilder, decorators: [{
  7506. type: Injectable,
  7507. args: [{ providedIn: 'root' }]
  7508. }] });
  7509. /**
  7510. * @module
  7511. * @description
  7512. * Entry point for all public APIs of the forms package.
  7513. */
  7514. /**
  7515. * @publicApi
  7516. */
  7517. const VERSION = new Version('19.2.4');
  7518. /**
  7519. * Exports the required providers and directives for template-driven forms,
  7520. * making them available for import by NgModules that import this module.
  7521. *
  7522. * @see [Forms Overview](guide/forms)
  7523. * @see [Template-driven Forms Guide](guide/forms)
  7524. *
  7525. * @publicApi
  7526. */
  7527. class FormsModule {
  7528. /**
  7529. * @description
  7530. * Provides options for configuring the forms module.
  7531. *
  7532. * @param opts An object of configuration options
  7533. * * `callSetDisabledState` Configures whether to `always` call `setDisabledState`, which is more
  7534. * correct, or to only call it `whenDisabled`, which is the legacy behavior.
  7535. */
  7536. static withConfig(opts) {
  7537. return {
  7538. ngModule: FormsModule,
  7539. providers: [
  7540. {
  7541. provide: CALL_SET_DISABLED_STATE,
  7542. useValue: opts.callSetDisabledState ?? setDisabledStateDefault,
  7543. },
  7544. ],
  7545. };
  7546. }
  7547. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  7548. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: FormsModule, declarations: [NgModel, NgModelGroup, NgForm], exports: [ɵInternalFormsSharedModule, NgModel, NgModelGroup, NgForm] });
  7549. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormsModule, imports: [ɵInternalFormsSharedModule] });
  7550. }
  7551. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormsModule, decorators: [{
  7552. type: NgModule,
  7553. args: [{
  7554. declarations: TEMPLATE_DRIVEN_DIRECTIVES,
  7555. exports: [ɵInternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES],
  7556. }]
  7557. }] });
  7558. /**
  7559. * Exports the required infrastructure and directives for reactive forms,
  7560. * making them available for import by NgModules that import this module.
  7561. *
  7562. * @see [Forms Overview](guide/forms)
  7563. * @see [Reactive Forms Guide](guide/forms/reactive-forms)
  7564. *
  7565. * @publicApi
  7566. */
  7567. class ReactiveFormsModule {
  7568. /**
  7569. * @description
  7570. * Provides options for configuring the reactive forms module.
  7571. *
  7572. * @param opts An object of configuration options
  7573. * * `warnOnNgModelWithFormControl` Configures when to emit a warning when an `ngModel`
  7574. * binding is used with reactive form directives.
  7575. * * `callSetDisabledState` Configures whether to `always` call `setDisabledState`, which is more
  7576. * correct, or to only call it `whenDisabled`, which is the legacy behavior.
  7577. */
  7578. static withConfig(opts) {
  7579. return {
  7580. ngModule: ReactiveFormsModule,
  7581. providers: [
  7582. {
  7583. provide: NG_MODEL_WITH_FORM_CONTROL_WARNING,
  7584. useValue: opts.warnOnNgModelWithFormControl ?? 'always',
  7585. },
  7586. {
  7587. provide: CALL_SET_DISABLED_STATE,
  7588. useValue: opts.callSetDisabledState ?? setDisabledStateDefault,
  7589. },
  7590. ],
  7591. };
  7592. }
  7593. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReactiveFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  7594. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: ReactiveFormsModule, declarations: [FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName], exports: [ɵInternalFormsSharedModule, FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName] });
  7595. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReactiveFormsModule, imports: [ɵInternalFormsSharedModule] });
  7596. }
  7597. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReactiveFormsModule, decorators: [{
  7598. type: NgModule,
  7599. args: [{
  7600. declarations: [REACTIVE_DRIVEN_DIRECTIVES],
  7601. exports: [ɵInternalFormsSharedModule, REACTIVE_DRIVEN_DIRECTIVES],
  7602. }]
  7603. }] });
  7604. export { AbstractControl, AbstractControlDirective, AbstractFormGroupDirective, COMPOSITION_BUFFER_MODE, CheckboxControlValueAccessor, CheckboxRequiredValidator, ControlContainer, ControlEvent, DefaultValueAccessor, EmailValidator, FormArray, FormArrayName, FormBuilder, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, FormRecord, FormResetEvent, FormSubmittedEvent, FormsModule, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgControlStatus, NgControlStatusGroup, NgForm, NgModel, NgModelGroup, NgSelectOption, NonNullableFormBuilder, NumberValueAccessor, PatternValidator, PristineChangeEvent, RadioControlValueAccessor, RangeValueAccessor, ReactiveFormsModule, RequiredValidator, SelectControlValueAccessor, SelectMultipleControlValueAccessor, StatusChangeEvent, TouchedChangeEvent, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, VERSION, Validators, ValueChangeEvent, isFormArray, isFormControl, isFormGroup, isFormRecord, ɵInternalFormsSharedModule, ɵNgNoValidate, ɵNgSelectMultipleOption };
  7605. //# sourceMappingURL=forms.mjs.map