Angular forms സാധാരണ HTML-മായി വളരെ മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു. input, textarea, select എന്നിവ അധിക പരിശ്രമമില്ലാതെ തന്നെ Reactive Forms-ലേക്ക് ഉൾപ്പെടുത്താം. ഇവയുടെ events, values, states എന്നിവ ഫ്രെയിംവർക്ക് കൃത്യമായി മനസ്സിലാക്കുന്നു.

എന്നാൽ ആധുനിക ആപ്ലിക്കേഷനുകൾക്ക് സാധാരണ എലമെന്റുകൾ മാത്രം മതിയാകില്ല. ഒരു star rating widget, ഒരു composite date selector, അല്ലെങ്കിൽ ഒരു custom color picker എന്നിവ നിങ്ങൾക്ക് ആവശ്യമായി വന്നേക്കാം. ഇവയിൽ ഏതെങ്കിലും ഒന്ന് ഒരു form group-ലേക്ക് ചേർത്താൽ, Angular അതിനെ വെറുമൊരു HTML ആയി മാത്രമേ കാണൂ. patchValue ഒന്നും ചെയ്യില്ല. Validators അവയെ അവഗണിക്കും. ഉപയോക്താവ് ആ control-മായി എപ്പോൾ ഇടപഴകുന്നു എന്ന് form-ന് അറിയില്ല, കൂടാതെ form.disable() ചെയ്താലും ആ custom widget പൂർണ്ണമായും പ്രവർത്തിച്ചുകൊണ്ടിരിക്കും.

ഈ പ്രശ്നം പരിഹരിക്കാനാണ് ControlValueAccessor നിലനിൽക്കുന്നത്.

ControlValueAccessor യഥാർത്ഥത്തിൽ എന്താണ് ചെയ്യുന്നത്

ഒരു custom component-നെ ഫോമിലെ ഒരു പ്രധാന ഘടകമായി (first-class citizen) മാറ്റുന്ന കരാറാണ് (contract) ControlValueAccessor. ഇത് Angular Forms API-യും നിങ്ങളുടെ സ്വന്തം UI-യും തമ്മിലുള്ള ഒരു വിവർത്തകൻ (translator) ആയി പ്രവർത്തിക്കുന്നു. നിങ്ങൾ ഇത് ശരിയായി നടപ്പിലാക്കിയാൽ, form-ന്റെ കാഴ്ചപ്പാടിൽ നിങ്ങളുടെ component ഒരു native input-ൽ നിന്നും വേർതിരിച്ചറിയാൻ കഴിയില്ല. ഒരു built-in element പോലെ തന്നെ ഇതിന് values സ്വീകരിക്കാനും, മാറ്റങ്ങൾ അറിയിക്കാനും (emit changes), touches റിപ്പോർട്ട് ചെയ്യാനും, disabled states പാലിക്കാനും കഴിയും.

ഈ interface-ന് നാല് പ്രത്യേക മെത്തേഡുകൾ ആവശ്യമാണ്. അവ ഓരോന്നും ആശയവിനിമയത്തിന്റെ വ്യത്യസ്ത ദിശകളെ കൈകാര്യം ചെയ്യുന്നു.

writeValue: Form-ൽ നിന്ന് Component-ലേക്ക്

writeValue(obj) എന്നത് ഇൻബൗണ്ട് (inbound) പാതയാണ്. ഫോം മോഡൽ അപ്‌ഡേറ്റ് ചെയ്യുമ്പോഴും പുതിയൊരു value നിങ്ങളുടെ UI-ലേക്ക് എത്തിക്കേണ്ടി വരുമ്പോഴും Angular ഈ മെത്തേഡ് വിളിക്കുന്നു. നിങ്ങൾ ഒരു form group-ൽ patchValue({ rating: 4 }) ഉപയോഗിച്ചാൽ, ആ 4 എന്ന value writeValue-ലൂടെ നിങ്ങളുടെ component-ലേക്ക് എത്തും. നിങ്ങൾ ഫോം റീസെറ്റ് ചെയ്യുകയാണെങ്കിൽ, writeValue പുതിയ initial value അല്ലെങ്കിൽ null സ്വീകരിക്കും. ഈ മെത്തേഡിനുള്ളിൽ നിങ്ങളുടെ ജോലി, ആ ഡാറ്റ സ്വീകരിച്ച് നിങ്ങളുടെ component-ന്റെ ആന്തരിക അവസ്ഥയിലേക്ക് (internal state) മാറ്റി നിർത്തുക എന്നതാണ്. നിങ്ങൾ ഒരു color picker നിർമ്മിക്കുകയാണെങ്കിൽ, writeValue #ff4400 പോലുള്ള ഒരു hex string സ്വീകരിക്കും, ആ നിറം സെലക്ട് ചെയ്തതായി കാണിക്കാൻ നിങ്ങൾ നിങ്ങളുടെ view അപ്‌ഡേറ്റ് ചെയ്യണം.

ഇവിടെ ഒരു പ്രായോഗികമായ ബുദ്ധിമുട്ടുണ്ട്. പ്രത്യേകിച്ച് ഡൈനാമിക് ആയി റെൻഡർ ചെയ്യുന്ന components, dialogs, അല്ലെങ്കിൽ tabbed interfaces എന്നിവയിൽ, നിങ്ങളുടെ view പൂർണ്ണമായി initialize ചെയ്യുന്നതിന് മുമ്പ് തന്നെ Angular writeValue വിളിച്ചേക്കാം. നിങ്ങളുടെ component വളരെ നേരത്തെ തന്നെ DOM-നെയോ ചൈൽഡ് components-നെയോ സ്പർശിക്കാൻ ശ്രമിച്ചാൽ runtime errors ഉണ്ടായേക്കാം. ഒരു മികച്ച രീതി എന്നത് value ഒരു local property-യിൽ സൂക്ഷിക്കുകയും view initialize ചെയ്ത ശേഷം അത് പ്രയോഗിക്കുകയും ചെയ്യുക എന്നതാണ്, അല്ലെങ്കിൽ undefined child references ഒഴിവാക്കാൻ ശ്രദ്ധിക്കുക. നിങ്ങളുടെ template സ്റ്റേബിൾ ആകുമ്പോൾ മാത്രമേ writeValue പ്രവർത്തിക്കൂ എന്ന് ഒരിക്കലും കരുതരുത്.

registerOnChange: Component-ൽ നിന്ന് Form-ലേക്ക്

registerOnChange(fn) എന്നത് ഔട്ട്ബൗണ്ട് (outbound) പാതയാണ്. Angular നിങ്ങൾക്ക് ഒരു callback function നൽകുന്നു, നിങ്ങൾ അതിന്റെ ഒരു reference സൂക്ഷിക്കേണ്ടതുണ്ട്. ഉപയോക്താവ് നിങ്ങളുടെ component-നുള്ളിലെ value മാറ്റുമ്പോഴെല്ലാം, നിങ്ങൾ ആ function പുതിയ value ഉപയോഗിച്ച് വിളിക്കണം. ഒരു star rating component-ൽ, ഉപയോക്താവ് മൂന്നാമത്തെ സ്റ്റാറിൽ ക്ലിക്ക് ചെയ്യുമ്പോൾ, നിങ്ങൾ സൂക്ഷിച്ച callback 3 എന്ന value-യുമായി വിളിക്കുന്നു. ആ കോൾ തിരികെ FormControl-ലേക്ക് എത്തുകയും, മോഡൽ അപ്‌ഡേറ്റ് ചെയ്യുകയും, ഏതെങ്കിലും valueChanges subscriptions പ്രവർത്തിപ്പിക്കുകയും, validators വീണ്ടും റൺ ചെയ്യുകയും ചെയ്യുന്നു.

ഈ ഘട്ടം ഒഴിവാക്കുന്നത് ഫോം പരാജയപ്പെടാൻ കാരണമാകുന്ന ഏറ്റവും സാധാരണമായ കാര്യമാണ്. വിഡ്ജറ്റ് പ്രവർത്തിക്കുന്നതായി തോന്നിയേക്കാം. സ്റ്റാറുകൾ തെളിയുന്നതോ, നിറങ്ങൾ മാറുന്നതോ, തീയതികൾ വരുന്നതോ ഉപയോക്താവ് കാണുന്നുണ്ടാകാം. എന്നാൽ ഫോം മോഡൽ ഒരിക്കലും അപ്‌ഡേറ്റ് ആകില്ല. Validators പഴയ ഡാറ്റ തന്നെ പരിശോധിച്ചുകൊണ്ടേയിരിക്കും. Submit handlers പഴയ values ആണ് അയക്കുന്നത്. component പ്രവർത്തിക്കുന്നതായി തോന്നുമെങ്കിലും ഫോം ശരിക്കും ഒന്നും അറിയുന്നില്ല. നിങ്ങളുടെ custom control ഉപയോക്താവിന്റെ ഇൻപുട്ട് സ്വീകരിക്കുന്നുണ്ടെങ്കിലും ചുറ്റുമുള്ള ഫോം അത് ശ്രദ്ധിക്കുന്നില്ലെങ്കിൽ, ഇതിന് കാരണം മിക്കവാറും ഇതാണ്.

registerOnTouched: Interaction റിപ്പോർട്ട് ചെയ്യുക

ഫോമുകൾ വെറും values മാത്രമല്ല ട്രാക്ക് ചെയ്യുന്നത്. ഒരു ഉപയോക്താവ് ഒരു ഫീൽഡുമായി ഇടപഴകിയോ (interacted) ഇല്ലയോ എന്നും അവ ട്രാക്ക് ചെയ്യുന്നു. Validation errors എപ്പോൾ കാണിക്കണം എന്ന് തീരുമാനിക്കാൻ Angular 'touched state' ഉപയോഗിക്കുന്നു. ഒരു required text input പേജ് ലോഡ് ആകുന്ന നിമിഷം തന്നെ ചുവപ്പ് നിറത്തിൽ തെളിയാൻ പാടില്ല. ഉപയോക്താവ് അവിടെ നിന്ന് മാറിപ്പോകുന്നത് വരെയോ അല്ലെങ്കിൽ മറ്റെവിടെയെങ്കിലും ക്ലിക്ക് ചെയ്യുന്നത് വരെയോ അത് കാത്തിരിക്കണം.

Native inputs blur events വഴി ഇത് സ്വയമേവ ചെയ്യുന്നു. എന്നാൽ custom components അങ്ങനെ ചെയ്യില്ല. ഈ ഇന്ററാക്ഷനുകൾ റിപ്പോർട്ട് ചെയ്യാൻ നിങ്ങൾ തന്നെ registerOnTouched(fn) ഉപയോഗിക്കണം. Angular നിങ്ങൾക്ക് മറ്റൊരു callback നൽകുന്നു; ഉപയോക്താവ് ആ control-മായി കൃത്യമായി ഇടപഴകിയെന്ന് നിങ്ങൾക്ക് തോന്നുമ്പോൾ നിങ്ങൾ അത് വിളിക്കണം.

ഇതിന്റെ കൃത്യമായ സമയം നിങ്ങളുടെ component-നെ ആശ്രയിച്ചിരിക്കും. ഒരു text-like custom input ആണെങ്കിൽ, blur സംഭവിക്കുമ്പോൾ നിങ്ങൾക്ക് ഇത് വിളിക്കാം. ഒരു star rating ആണെങ്കിൽ, ആദ്യത്തെ ക്ലിക്ക് ആയിരിക്കാം ശരിയായ സമയം. ഒരു popover തുറക്കുന്ന color picker ആണെങ്കിൽ, palette അടയുന്നത് വരെ കാത്തിരിക്കാം. ഇതിൽ ഏറ്റവും പ്രധാനം കൃത്യതയാണ് (consistency). നിങ്ങൾ ഒരിക്കലും touched callback വിളിച്ചില്ലെങ്കിൽ, Angular ആ control-നെ 'pristine' ആയി തന്നെ കണക്കാക്കും. ഉപയോക്താവ് എഡിറ്റിംഗ് പൂർത്തിയാക്കിയ ശേഷവും validation errors മറഞ്ഞിരിക്കും. ഇത് ആശയക്കുഴപ്പത്തിനും മോശം യൂസർ എക്സ്പീരിയൻസിനും കാരണമാകും.

setDisabledState: ഫോം കമാൻഡുകൾ അനുസരിക്കുക

ബിസിനസ് ലോജിക് അനുസരിച്ച് ഡൈനാമിക് ഫോമുകൾ നിരന്തരം ഫീൽഡുകൾ എനേബിൾ ചെയ്യുകയും ഡിസേബിൾ ചെയ്യുകയും ചെയ്യുന്നു. നിങ്ങൾ ഒരു FormControl-ൽ .disable() എന്ന് വിളിക്കുമ്പോൾ, നിങ്ങളുടെ കസ്റ്റം കംപോണന്റ് അതിനോട് പ്രതികരിക്കേണ്ടതുണ്ട്. setDisabledState(isDisabled) ഒരു ബൂലിയൻ (boolean) സ്വീകരിക്കുന്നു. ഇത് true ആണെങ്കിൽ, നിങ്ങൾ നിങ്ങളുടെ UI ലോക്ക് ചെയ്യണം.

ഇതിനർത്ഥം വെറുതെ ക്ലിക്കുകൾ അവഗണിക്കുക എന്നതല്ല. നിങ്ങൾ ആന്തരിക ബട്ടണുകൾ ഡിസേബിൾ ചെയ്യണം, ഫോക്കസ് ചെയ്യാവുന്ന അവസ്ഥകൾ (focusable states) നീക്കം ചെയ്യണം, കൂടാതെ കുറഞ്ഞ ഓപാസിറ്റി (reduced opacity) അല്ലെങ്കിൽ pointer-events: none പോലുള്ള വിഷ്വൽ മാറ്റങ്ങൾ വരുത്തുകയും വേണം. നിങ്ങൾ ഈ മെത്തേഡ് അവഗണിച്ചാൽ, ഫോം മോഡൽ അത് ഡിസേബിൾ ആണെന്ന് പറയുമ്പോഴും നിങ്ങളുടെ കംപോണന്റ് പൂർണ്ണമായും ഇന്ററാക്ടീവ് ആയി തുടരും. ഇത് കണ്ടെത്താൻ പ്രയാസമുള്ള ബഗുകൾ (bugs) ഉണ്ടാക്കുന്നു. ഫോം നിരസിക്കേണ്ട മൂല്യങ്ങൾ ഉപയോക്താക്കൾക്ക് മാറ്റാൻ സാധിക്കും. തെറ്റായ അവസ്ഥകളുടെ അടിസ്ഥാനത്തിൽ സേവ് ബട്ടണുകൾ എനേബിൾ ആയേക്കാം. ഫോം ഗ്രൂപ്പും UI-യും തമ്മിൽ വ്യത്യാസം വരുന്നു.

കൃത്യമായി നിർമ്മിച്ച ഒരു കസ്റ്റം കൺട്രോൾ setDisabledState-നെ ഒരു പ്രധാന ആവശ്യകതയായി കാണുന്നു, അല്ലാതെ പിന്നീട് ശ്രദ്ധിക്കേണ്ട ഒന്നായിട്ടല്ല.

ഡീബഗ്ഗിംഗ് സമയം നഷ്ടപ്പെടുത്തുന്ന തെറ്റുകൾ

ഈ ഇന്റർഫേസുമായി പരിചയമില്ലാത്ത ഡെവലപ്പർമാർ ആവർത്തിച്ചു വരുത്തുന്ന ചില തെറ്റുകൾ താഴെ പറയുന്നവയാണ്.

ചേഞ്ച് കോൾബാക്ക് (change callback) വിളിക്കാൻ മറന്നുപോകുന്നു. നിങ്ങളുടെ കംപോണന്റ് അതിന്റെ ആന്തരിക അവസ്ഥ (internal state) അപ്ഡേറ്റ് ചെയ്യുന്നുണ്ടെങ്കിലും ഫോമിന് അതിനെക്കുറിച്ച് അറിയിപ്പ് ലഭിക്കുന്നില്ല. ഇത് വാലിഡേറ്ററുകളെ (validators) തടസ്സപ്പെടുത്തുകയും പാരന്റ് ഫോമുകൾ പഴയ ഡാറ്റ (stale data) സബ്മിറ്റ് ചെയ്യുകയും ചെയ്യുന്നു. ഉപയോക്താവ് ഒരു പുതിയ മൂല്യം നൽകുന്ന നിമിഷം തന്നെ ആ സ്റ്റോർ ചെയ്ത onChange ഫംഗ്ഷൻ എപ്പോഴും പ്രവർത്തിപ്പിക്കുക.

ടച്ച്ഡ് കോൾബാക്ക് (touched callback) ഒഴിവാക്കുന്നു. ഇത് ഇല്ലാതെ, Angular കൺട്രളിനെ ഒരിക്കലും 'touched' ആയി അടയാളപ്പെടുത്തില്ല. touched അല്ലെങ്കിൽ dirty അവസ്ഥകളുമായി ബന്ധപ്പെട്ട എറർ മെസ്സേജുകൾ കാണിക്കപ്പെടില്ല. ഫോം ശരിയാണെന്ന് തോന്നുമെങ്കിലും സബ്മിറ്റ് ആകില്ല, എന്താണ് തെറ്റായതെന്നതിനെക്കുറിച്ച് ഉപയോക്താവിന് യാതൊരു സൂചനയും ലഭിക്കില്ല.

ഡിസേബിൾ ചെയ്ത അവസ്ഥ അവഗണിക്കുന്നു. വിഷ്വലായി എനേബിൾ ചെയ്ത ഒരു കൺട്രോൾ ഫോമിന് ഡിസേബിൾ ആണെന്ന് തോന്നിയാൽ അത് വിശ്വാസ്യത കുറയ്ക്കുന്നു. ഉപയോക്താവിന് ടൈപ്പ് ചെയ്യാനോ ക്ലിക്ക് ചെയ്യാനോ സാധിക്കും, പക്ഷേ മോഡൽ അവരെ അവഗണിക്കും. അല്ലെങ്കിൽ കൂടുതൽ മോശമായത്, സിങ്ക് സൈക്കിളുകൾക്കിടയിൽ മോഡൽ അവരുടെ ഇൻപുട്ട് ഇടയ്ക്കിടെ ഓവർറൈറ്റ് ചെയ്തേക്കാം.

NG_VALUE_ACCESSOR പ്രൊവൈഡർ ഒഴിവാക്കുന്നു. ഇതാണ് ഏറ്റവും വലിയ പ്രശ്നം. നിങ്ങൾ നാല് മെത്തേഡുകളും നടപ്പിലാക്കിയെങ്കിലും കംപോണന്റിന്റെ providers അറേയിൽ NG_VALUE_ACCESSOR ചേർക്കാൻ മറന്നാൽ, Angular നിങ്ങളുടെ കംപോണന്റിനെ ഒരു വാല്യൂ ആക്സസ്സറായി (value accessor) രജിസ്റ്റർ ചെയ്യില്ല. കോഡ് കംപൈൽ ചെയ്യും, വ്യൂ റെൻഡർ ചെയ്യും, പക്ഷേ ഒന്നും ബൈൻഡ് ആകില്ല. ഒരു എറർ മെസ്സേജും ലഭിക്കില്ല, പകരം കംപോണന്റ് ഫോമിന് പുറത്ത് നിൽക്കുന്ന അവസ്ഥയിലാകും. എപ്പോഴും ഡെക്കറേറ്റർ മെറ്റാഡാറ്റയിൽ (decorator metadata) ഇത് ഉൾപ്പെടുത്തുക.

സിഗ്നലുകൾ, വാലിഡേറ്ററുകൾ, മോഡേൺ Angular

ControlValueAccessor എന്നത് പഴയ (legacy) ഒരു API അല്ല. ഇത് ആധുനിക Angular ഡെവലപ്‌മെന്റിൽ കൃത്യമായി ഇണങ്ങിച്ചേരുന്നു. നിങ്ങൾ ആന്തരിക അവസ്ഥകൾ Signals, സാധാരണ പ്രോപ്പർട്ടികൾ അല്ലെങ്കിൽ RxJS subjects എന്നിവ ഉപയോഗിച്ച് കൈകാര്യം ചെയ്താലും, ആ നാല് മെത്തേഡുകൾ ഫോംസ് മോഡ്യൂളുമായുള്ള നിങ്ങളുടെ കരാറായി തുടരുന്നു. നിങ്ങൾ writeValue-ൽ മൂല്യങ്ങൾ സ്വീകരിക്കുന്നു, നിങ്ങളുടെ Signals അല്ലെങ്കിൽ സ്റ്റേറ്റ് മാറ്റം വരുത്തുന്നു, കൂടാതെ Angular നൽകുന്ന കോൾബാക്കുകൾ വഴി അവ പുറത്തേക്ക് വിടുന്നു.

സ്റ്റാൻഡേർഡ് വാലിഡേറ്ററുകൾ മാറ്റങ്ങളില്ലാതെ തന്നെ പ്രവർത്തിക്കും. Validators.required, Validators.min, Validators.pattern, കൂടാതെ കസ്റ്റം ക്രോസ്-ഫീൽഡ് വാലിഡേറ്ററുകൾ എന്നിവയെല്ലാം നിങ്ങളുടെ CVA-അധിഷ്ഠിത കംപോണന്റിനെ ഒരു നേറ്റീവ് ഇൻപുട്ട് പോലെ തന്നെ വിലയിരുത്തുന്നു. ഫോം കൺട്രോൾ ഒരു മൂല്യവും (value) അതിന്റെ അവസ്ഥയും (state) മാത്രമേ കാണുന്നുള്ളൂ. ആ മൂല്യം ഒരു ടെക്സ്റ്റ് ബോക്സിൽ നിന്നാണോ അതോ നിങ്ങൾ നിർമ്മിച്ച ഒരു മന്ത്-പിക്കറിൽ (month-picker) നിന്നാണോ വന്നതെന്ന് അത് ശ്രദ്ധിക്കുന്നില്ല.

ഈ പോർട്ടബിലിറ്റിയാണ് (portability) ഡിസൈൻ സിസ്റ്റങ്ങൾക്കും ഷെയർഡ് UI ലൈബ്രറികൾക്കും CVA പ്രധാനമാകാൻ കാരണം. ഒരു ടീം ശക്തമായ ഒരു ഫോൺ നമ്പർ ഇൻപുട്ട് അല്ലെങ്കിൽ ഫയൽ അപ്‌ലോഡ് വിഡ്ജറ്റ് നിർമ്മിക്കുന്നു. അവർ ആ ഇന്റർഫേസ് ഒരിക്കൽ നടപ്പിലാക്കുന്നു. സംഘടനയിലെ മറ്റ് എല്ലാ ടീമുകൾക്കും അധികമായ കോഡിംഗ് ഇല്ലാതെ തന്നെ അത് അവരുടെ Reactive Forms-ൽ ഉപയോഗിക്കാം. ഓരോ ഫീച്ചർ മോഡ്യൂളിലും കംപോണന്റ് കൃത്യമായി പ്രവർത്തിക്കുകയും, ഒരേപോലെ വാലിഡേറ്റ് ചെയ്യുകയും, ഒരേപോലെ ഡിസേബിൾ ആകുകയും ചെയ്യുന്നു.

യഥാർത്ഥ പാഠം

ControlValueAccessor എന്നത് ഇന്റർവ്യൂ ചോദ്യങ്ങൾക്കായി മനഃപാഠമാക്കേണ്ട വെറുമൊരു ഇന്റർഫേസ് മാത്രമല്ല. നിങ്ങളുടെ കസ്റ്റം കംപോണന്റുകളെ നേറ്റീവ് HTML എലമെന്റുകൾക്ക് തുല്യമായി Angular-ന്റെ ഫോം ഇക്കോസിസ്റ്റത്തിൽ പങ്കാളികളാക്കാൻ സഹായിക്കുന്ന ഒരു പാലമാണിത്. ഇത് മാസ്റ്റർ ചെയ്യുക എന്നാൽ നിങ്ങളുടെ വിഡ്ജറ്റും ഫോമും തമ്മിലുള്ള പൂർണ്ണമായ ആശയവിനിമയം മനസ്സിലാക്കുക എന്നാണ് അർത്ഥം: മൂല്യങ്ങൾ സ്വീകരിക്കുക, മാറ്റങ്ങൾ റിപ്പോർട്ട് ചെയ്യുക, ടച്ചുകൾ അറിയിക്കുക, ഡിസേബിൾ ചെയ്ത അവസ്ഥകൾ അനുസരിക്കുക എന്നിവയാണവ. ഈ നാല് കാര്യങ്ങൾ കൃത്യമായി ചെയ്താൽ, അവ ഉപയോഗിക്കുന്ന ഡെവലപ്പർമാർക്ക് വളരെ ലളിതമായി തോന്നുന്ന സങ്കീർണ്ണവും പുനരുപയോഗിക്കാവുന്നതുമായ ഫോം കൺട്രോളുകൾ നിങ്ങൾക്ക് നിർമ്മിക്കാം. അതാണ് ഒരു പ്രൊഫഷണൽ Angular കംപോണന്റിന്റെ ലക്ഷണം.