Vue 3 फॉर्म आर्किटेक्चर व्यवसायिक ऐप्स के लिए: पुन: उपयोग योग्य पैटर्न
Vue 3 फॉर्म आर्किटेक्चर बिजनेस ऐप्स के लिए: पुन: उपयोग योग्य फील्ड कंपोनेंट्स, स्पष्ट सत्यापन नियम, और सर्वर त्रुटियों को हर इनपुट पर दिखाने के व्यावहारिक तरीके।

क्यों असली बिज़नेस ऐप्स में फॉर्म कोड टूटने लगता है
बिज़नेस ऐप में एक फॉर्म मुश्किल से ही छोटा ही रहता है। यह "सिर्फ कुछ इनपुट्स" के रूप में शुरू होता है, फिर दर्जनों फ़ील्ड, कंडीशनल सेक्शन, परमिशन और नियमों में बढ़ जाता है जिन्हें बैकएंड लॉजिक के साथ सिंक में रखना होता है। कुछ प्रोडक्ट बदलावों के बाद, फॉर्म काम करता रहता है, लेकिन कोड नाज़ुक सा लगने लगता है।
Vue 3 फॉर्म आर्किटेक्चर मायने रखता है क्योंकि फॉर्म वही जगह हैं जहाँ "क्विक फिक्स" जमा हो जाते हैं: एक और watcher, एक और स्पेशल केस, एक और कॉपी किया हुआ कंपोनेंट। आज यह काम करता है, पर भरोसा करना और बदलना कठिन हो जाता है।
चेतावनी के संकेत परिचित हैं: पेजों में बार-बार दोहराई गई इनपुट बिहेवियर (लेबल, फॉर्मेटिंग, आवश्यक मार्कर, हिन्ट), असंगत त्रुटि प्लेसमेंट, सत्यापन नियमों का कंपोनेंट्स में बिखरना, और बैकएंड त्रुटियों का एक सामान्य टोस्ट बन जाना जो उपयोगकर्ताओं को नहीं बताता कि क्या ठीक करना है।
ये असंगतताएँ केवल कोड स्टाइल की समस्याएँ नहीं हैं। वे UX समस्याओं में बदलती हैं: लोग फॉर्म दोबारा सबमिट करते हैं, सपोर्ट टिकट बढ़ते हैं, और टीमें फॉर्म्स को छूने से डरती हैं क्योंकि कोई छुपा हुआ एज केस टूट सकता है।
एक अच्छा सेटअप फॉर्म्स को सबसे अच्छी तरह से बोरिंग बना देता है। एक पूर्वानुमेय संरचना के साथ आप फ़ील्ड जोड़ सकते हैं, नियम बदल सकते हैं, और सर्वर प्रतिक्रियाओं को हैंडल कर सकते हैं बिना हर चीज़ को फिर से वायर किए।
आप ऐसी फॉर्म सिस्टम चाहते हैं जो आपको रीयूज़ दे (एक फील्ड हर जगह एक जैसा व्यवहार करे), स्पष्टता दे (नियम और त्रुटि हैंडलिंग आसानी से रिव्यू हो सके), पूर्वानुमेय बिहेवियर दे (touched, dirty, reset, submit), और बेहतर फीडबैक दे (सर्वर-साइड त्रुटियाँ उसी इनपुट पर दिखें जिसे एक्शन चाहिए)। नीचे दिए पैटर्न पुन: उपयोग योग्य फील्ड कंपोनेंट्स, पठनीय सत्यापन, और सर्वर त्रुटियों का सर्व-इनपुट मैपिंग पर केंद्रित हैं।
फॉर्म संरचना के लिए एक सरल मानसिक मॉडल
एक ऐसा फॉर्म जो समय के साथ टिके रहता है, वह स्पष्ट भागों वाला एक छोटा सिस्टम होता है, न कि इनपुट्स का ढेर।
चार परतों के बारे में सोचें जो एक-दूसरे से एक दिशा में बोलती हैं: UI इनपुट इकट्ठा करती है, फॉर्म स्टेट उसे स्टोर करता है, वैलिडेशन बताता है क्या गलत है, और API लेयर लोड/सेव करती है।
चार परतें (और हर एक का अधिकार)
- Field UI component: इनपुट, लेबल, हिन्ट और त्रुटि टेक्स्ट रेंडर करता है। वैल्यू चेंज एमिट करता है।
- Form state: वैल्यूज़ और एरर्स रखता है (साथ में touched और dirty फ़्लैग)।
- Validation rules: शुद्ध फ़ंक्शन्स जो वैल्यूज़ पढ़ते हैं और त्रुटि संदेश लौटाते हैं।
- API calls: प्रारंभिक डेटा लोड करना, बदलाव सबमिट करना, और सर्वर प्रतिक्रियाओं को फील्ड एरर्स में ट्रांसलेट करना।
यह अलगाव बदलावों को सीमित रखता है। जब कोई नया आवश्यकता आती है, आप एक परत को अपडेट करके बाकी को नहीं तोड़ते।
फील्ड में क्या होना चाहिए और पैरेंट फॉर्म में क्या
एक पुन: उपयोग योग्य फील्ड कंपोनेंट बोरिंग होना चाहिए। इसे आपके API, डेटा मॉडल, या सत्यापन नियमों के बारे में नहीं पता होना चाहिए। इसे केवल एक वैल्यू दिखानी चाहिए और त्रुटि दिखानी चाहिए।
पैरेंट फॉर्म बाकी सब कुछ समन्वयित करता है: कौन से फील्ड मौजूद हैं, वैल्यूज़ कहाँ रहती हैं, कब वैलिडेट करना है, और कैसे सबमिट करना है।
एक सरल नियम मदद करता है: यदि लॉजिक अन्य फील्ड्स पर निर्भर है (उदाहरण: "State" तभी आवश्यक है जब "Country" US हो), तो उसे फील्ड कंपोनेंट के अंदर नहीं, पैरेंट फॉर्म या वैलिडेशन लेयर में रखें।
जब नया फील्ड जोड़ना वास्तव में कम मेहनत वाला हो, तो आप आम तौर पर केवल डिफ़ॉल्ट्स या स्कीमा, उस मार्कअप जहाँ फील्ड रखा गया है, और फील्ड के वैलिडेशन नियमों को छूते हैं। यदि एक इनपुट जोड़ने से अप्रसंगिक कंपोनेंट्स में बदलाव मजबूर हों, तो आपकी सीमाएँ धुंधली हैं।
पुन: उपयोग योग्य फील्ड कंपोनेंट्स: किस चीज़ को स्टैण्डर्डाइज़ करें
जब फॉर्म बढ़ते हैं, सबसे तेज़ लाभ यह है कि हर इनपुट को एक-ऑफ की तरह बनाना बंद कर दें। फील्ड कंपोनेंट्स को पूर्वानुमेय महसूस करना चाहिए। यही उन्हें तेज़ बनाता है और रिव्यू करना आसान बनाता है।
व्यावहारिक बिल्डिंग ब्लॉक्स का एक सेट:
- BaseField: लेबल, हिन्ट, त्रुटि टेक्स्ट, स्पेसिंग और एक्सेसिबिलिटी एट्रिब्यूट्स के लिए रैपर।
- Input components: TextInput, SelectInput, DateInput, Checkbox, आदि। प्रत्येक कंट्रोल पर केन्द्रित।
- FormSection: संबंधित फील्ड्स को शीर्षक, छोटा हेल्प टेक्स्ट और सुसंगत स्पेसिंग के साथ ग्रुप करता है।
प्रॉप्स के लिए एक छोटा सेट रखें और हर जगह उसे लागू करें। 40 फॉर्म्स में किसी प्रॉप का नाम बदलना दर्दनाक होता है।
ये आम तौर पर तुरंत लाभ देते हैं:
modelValueऔरupdate:modelValueforv-modellabelrequireddisablederror(सिंगल मैसेज, या यदि आप चाहें तो एक एरे)hint
Slots वह जगह हैं जहाँ आप लचीलापन देते हैं बिना स्थिरता तोड़े। BaseField लेआउट को स्थिर रखें, पर छोटे वेरिएशंस जैसे दाहिनी तरफ एक्शन ("Send code") या लीडिंग आइकन की अनुमति दें। अगर कोई वेरिएशन दो बार आता है, तो उसे स्लॉट बनाएं बजाय कंपोनेंट फोर्क करने के।
रेंडर ऑर्डर को स्टैण्डर्डाइज़ करें (लेबल, कंट्रोल, हिन्ट, त्रुटि)। उपयोगकर्ता तेज़ी से स्कैन करते हैं, टेस्ट सरल होते हैं, और सर्वर एरर मैपिंग सीधे-सादा हो जाती है क्योंकि हर फील्ड के पास संदेश दिखाने की एक स्पष्ट जगह होती है।
फॉर्म स्टेट: values, touched, dirty, और reset
बिज़नेस ऐप्स में अधिकांश फॉर्म बग्स इनपुट्स के बारे में नहीं होते। वे बिखरे हुए स्टेट के बारे में होते हैं: वैल्यूज़ एक जगह, त्रुटियाँ दूसरी जगह, और एक रिसेट बटन जो आधा काम करता है। एक साफ़ Vue 3 फॉर्म आर्किटेक्चर एक सुसंगत स्टेट शेप से शुरू होता है।
पहले, फील्ड कीज़ के लिए एक नामकरण स्कीम चुनें और उस पर टिके रहें। सबसे सरल नियम है: फील्ड की, API पेलोड की कुँजी के बराबर हो। यदि आपका सर्वर first_name उम्मीद करता है, तो आपके फॉर्म की की first_name ही होनी चाहिए। यह छोटा सा निर्णय वैलिडेशन, सेविंग, और सर्वर एरर मैपिंग को बहुत आसान बनाता है।
अपना फॉर्म स्टेट एक जगह रखें (एक कॉम्बोजेबल, Pinia स्टोर, या पैरेंट कंपोनेंट), और हर फील्ड उस स्टेट के माध्यम से पढ़े और लिखे। एक फ्लैट स्ट्रक्चर अधिकांश स्क्रीन के लिए काम करता है। जब तक आपका API वास्तव में नेस्टेड न हो, तब तक नेस्टिंग न करें。
const state = reactive({
values: { first_name: '', last_name: '', email: '' },
touched: { first_name: false, last_name: false, email: false },
dirty: { first_name: false, last_name: false, email: false },
errors: { first_name: '', last_name: '', email: '' },
defaults: { first_name: '', last_name: '', email: '' }
})
फ्लैग्स के बारे में सोचने का व्यावहारिक तरीका:
touched: क्या उपयोगकर्ता ने इस फील्ड के साथ इंटरैक्ट किया है?dirty: क्या वैल्यू डिफ़ॉल्ट (या आखिरी सहेजे गए) मान से अलग है?errors: अभी उपयोगकर्ता को कौन सा संदेश दिखाना चाहिए?defaults: हम किस पर वापस रीसेट करेंगे?
रीसेट बिहेवियर अनुमान्य होना चाहिए। जब आप एक मौजूदा रिकॉर्ड लोड करते हैं, तो values और defaults दोनों को एक ही स्रोत से सेट करें। फिर reset() defaults को values में कॉपी कर सकता है, touched और dirty को क्लियर कर सकता है, और errors को भी क्लियर कर सकता है।
उदाहरण: एक कस्टमर प्रोफ़ाइल फॉर्म सर्वर से email लोड करता है। यदि उपयोगकर्ता उसे एडिट करता है, तो dirty.email true हो जाता है। यदि वे Reset क्लिक करते हैं, तो ईमेल वापस लोड किए गए मान पर आ जाएगा (खाली स्ट्रिंग नहीं), और स्क्रीन फिर से साफ दिखेगी।
पठनीय रहने वाले सत्यापन नियम
पठनीय वैलिडेशन लाइब्रेरी से अधिक इस बात पर निर्भर करता है कि आप नियम कैसे लिखते हैं। यदि आप एक फील्ड पर एक नजर में उसके नियम समझ सकें, तो आपका फॉर्म कोड मेंटेनबल रहता है।
एक नियम शैली चुनें जिसे आप अपनाएँ
अधिकांश टीमें इनमें से एक अपनाती हैं:
- Per-field rules: नियम फील्ड के उपयोग के पास रहते हैं। स्कैन करने में आसान, छोटे से मध्यम फॉर्म्स के लिए बढ़िया।
- Schema-based rules: नियम एक ऑब्जेक्ट या फ़ाइल में रहते हैं। जब कई स्क्रीन एक ही मॉडल को रीयूज़ करती हैं तो यह अच्छा रहता है।
- Hybrid: सरल नियम फील्ड के पास, साझा या जटिल नियम केंद्रीय स्कीमा में।
जो भी आप चुनें, नियमों के नाम और संदेशों को अनुमान्य रखें। कुछ सामान्य नियम (required, length, format, range) कई एक-ऑफ हेल्पर्स से बेहतर हैं।
नियमों को साधारण अंग्रेज़ी जैसा लिखें
एक अच्छा नियम वाक्य जैसा पढ़ना चाहिए: "Email आवश्यक है और ईमेल जैसा दिखना चाहिए।" चालाक एक-लाइनर से बचें जो इरादे छुपा दे।
अधिकांश बिज़नेस फॉर्म्स के लिए, एक समय में प्रति फील्ड एक संदेश लौटाना (पहली विफलता) UI को शांत रखता है और उपयोगकर्ताओं को तेज़ी से समस्या ठीक करने में मदद करता है।
सामान्य नियम जो उपयोगकर्ता-मित्रवत रहते हैं:
- Required केवल जब उपयोगकर्ता को सचमुच भरना ही है।
- Length वास्तविक संख्याओं के साथ (उदा., 2 से 50 वर्ण)।
- Format ईमेल, फ़ोन, ZIP के लिए, बिना इतनी कड़ी regex के जो वास्तविक इनपुट को अस्वीकार कर दे।
- Range जैसे "तारीख भविष्य में नहीं हो" या "quantity 1 और 999 के बीच"।
असिंक्रोनस चेक्स को स्पष्ट बनाएं
"username लिया गया है" जैसे असिंक्रोनस वैलिडेशन भ्रमित कर देते हैं यदि वे मौन रूप से चलते हैं।
ब्लर पर या छोटे ब्रेक के बाद चेक ट्रिगर करें, एक स्पष्ट "Checking..." स्टेट दिखाएँ, और जब उपयोगकर्ता टाइप करते रहें तो आउटडेटेड अनुरोध रद्द या अनदेखा कर दें।
निर्णय लें कि वैलिडेशन कब चलेगा
टiming नियमों जितना मायने रखता है उतना ही नियम। एक उपयोगकर्ता-मित्रवत सेटअप यह है:
- On change उन फील्ड्स के लिए जिनमें लाइव फीडबैक फायदेमंद है (जैसे पासवर्ड स्ट्रेंथ), पर इसे सौम्य रखें।
- On blur अधिकांश फील्ड्स के लिए, ताकि उपयोगकर्ता बिना लगातार त्रुटियों के टाइप कर सके।
- On submit पूरे फॉर्म के लिए अंतिम सुरक्षा जाल के रूप में।
सर्वर त्रुटियों को सही इनपुट से मैप करना
क्लाइंट-साइड चेक्स कहानी का सिर्फ आधा हिस्सा हैं। बिज़नेस ऐप्स में सर्वर ऐसे नियमों के लिए सेव को रिजेक्ट कर देता है जिन्हें ब्राउज़र नहीं जान सकता: डुप्लिकेट्स, परमिशन चेक, स्टेल डेटा, स्टेट परिवर्तन, और बहुत कुछ। अच्छा फॉर्म UX इस प्रतिक्रिया को स्पष्ट संदेशों में बदलने पर निर्भर करता है जो सही इनपुट के पास दिखें।
त्रुटियों को एक आंतरिक शेप में सामान्यीकृत करें
बैकएंड्स शायद त्रुटि फ़ॉर्मैट में सहमत न हों। कुछ एक ऑब्जेक्ट लौटाते हैं, कुछ लिस्ट, कुछ नेस्टेड मैप्स फ़ील्ड नेम के साथ। जो कुछ भी आप पाते हैं उसे एक ही आंतरिक शेप में बदल दें जिसे आपका फॉर्म रेंडर कर सके।
// what your form code consumes
{
fieldErrors: { "email": ["Already taken"], "address.street": ["Required"] },
formErrors: ["You do not have permission to edit this customer"]
}
कुछ नियम सुसंगत रखें:
- फील्ड एरर्स को एरे के रूप में स्टोर करें (भले ही सिर्फ एक संदेश हो)।
- अलग-अलग पाथ शैलियों को एक स्टाइल में बदलें (डॉट पाथ अच्छी तरह काम करते हैं:
address.street)। - नॉन-फील्ड एरर्स अलग रखें जैसे
formErrors। - लॉगिंग के लिए रॉ सर्वर पेलोड रखें, पर उसे रेंडर न करें।
सर्वर पाथ्स को अपने फील्ड कीज़ से मैप करें
मुश्किल हिस्सा सर्वर के "पाथ" के विचार को आपके फॉर्म की फील्ड कीज़ के साथ मेल खाना है। हर फील्ड कंपोनेंट के लिए एक की तय करें (उदा., email, profile.phone, contacts.0.type) और उस पर टिके रहें।
फिर एक छोटा मैपर लिखें जो आम केस हैंडल करे:
address.street(डॉट नोटेशन)address[0].street(ऐरे के लिए ब्रैकेट)/address/street(JSON Pointer स्टाइल)
नॉर्मलाइज़ेशन के बाद, <Field name="address.street" /> को fieldErrors["address.street"] बिना स्पेशल केस के पढ़ना चाहिए।
ज़रूरत पड़ने पर एलियासेस का समर्थन करें। यदि बैकएंड customer_email लौटाता है लेकिन आपका UI email उपयोग करता है, तो नॉर्मलाइज़ेशन के दौरान { customer_email: "email" } जैसा मैप रखें।
फील्ड एरर्स, फॉर्म-लेवल एरर्स, और फोकसिंग
हर त्रुटि किसी एक इनपुट की नहीं होती। अगर सर्वर कहता है "Plan limit reached" या "Payment required," तो इसे फॉर्म के ऊपर फॉर्म-लेवल संदेश के रूप में दिखाएँ।
फील्ड-विशिष्ट त्रुटियों के लिए, संदेश इनपुट के पास दिखाएँ और उपयोगकर्ता को पहले समस्या की ओर निर्देशित करें:
- सर्वर एरर्स सेट करने के बाद,
fieldErrorsमें पहले उस की को खोजें जो आपके रेंडर किए गए फॉर्म में मौजूद हो। - उसे व्यू में स्क्रॉल करें और फोकस करें (प्रति फील्ड ref और
nextTickका उपयोग)। - जब उपयोगकर्ता उस फील्ड को फिर से एडिट करे तो उस फील्ड की सर्वर त्रुटियाँ साफ़ कर दें।
कदम दर कदम: आर्किटेक्चर को एक साथ लगाना
जब आप पहले तय कर लें कि क्या फॉर्म स्टेट, UI, वैलिडेशन, और API में आता है, और फिर उन्हें कुछ छोटे फ़ंक्शन्स से जोड़ें, तो फॉर्म शांत रहते हैं।
एक सेक्वेंस जो अधिकांश बिज़नेस ऐप्स के लिए काम करता है:
- एक फॉर्म मॉडल और स्थिर फील्ड कीज़ के साथ शुरू करें। वे कीज़ कंपोनेंट्स, वेलिडेटर्स, और सर्वर एरर्स के बीच कॉन्ट्रैक्ट बन जाती हैं।
- एक BaseField रैपर बनाएँ जो लेबल, हेल्प टेक्स्ट, आवश्यक मार्क और त्रुटि डिस्प्ले संभाले। इनपुट कंपोनेंट्स को छोटा और सुसंगत रखें।
- एक वैलिडेशन लेयर जोड़ें जो प्रति फील्ड चल सके और सबमिट पर सब कुछ सत्यापित कर सके।
- API को सबमिट करें। अगर यह फेल हो, तो सर्वर एरर्स को
{ [fieldKey]: message }में ट्रांसलेट करें ताकि सही इनपुट सही संदेश दिखाए। - सफलता हैंडलिंग को अलग रखें (रीसेट, टोस्ट, नेविगेट) ताकि यह कंपोनेंट्स और वेलिडेटर्स में रिस न कर सके।
स्टेट के लिए एक सरल शुरुआती बिंदु:
const values = reactive({ email: '', name: '', phone: '' })
const touched = reactive({ email: false, name: false, phone: false })
const errors = reactive({}) // { email: '...', name: '...' }
आपका BaseField label, error, और शायद touched पाता है, और एक ही जगह संदेश रेंडर करता है। हर इनपुट कंपोनेंट केवल बाइंडिंग और अपडेट एमिट करने की चिंता करता है।
वेलिडेशन के लिए, मॉडल के पास ही नियम रखें और उन्हीं कीज़ का उपयोग करें:
const rules = {
email: v => (!v ? 'Email is required' : /@/.test(v) ? '' : 'Enter a valid email'),
name: v => (v.length < 2 ? 'Name is too short' : ''),
}
function validateAll() {
Object.keys(rules).forEach(k => {
const msg = rules[k](values[k])
if (msg) errors[k] = msg
else delete errors[k]
touched[k] = true
})
return Object.keys(errors).length === 0
}
जब सर्वर एरर्स लौटाता है, तो उन्हें उसी कीज़ का उपयोग करके मैप करें। अगर API { "field": "email", "message": "Already taken" } लौटाए, तो errors.email = 'Already taken' सेट करें और उसे touched मार्क करें। अगर एरर ग्लोबल है (जैसे "permission denied"), तो उसे फॉर्म के ऊपर दिखाएँ।
उदाहरण परिदृश्य: कस्टमर प्रोफ़ाइल एडिट करना
एक अंदरूनी एडमिन स्क्रीन की कल्पना करें जहाँ एक सपोर्ट एजेंट कस्टमर प्रोफ़ाइल संपादित करता है। फॉर्म में चार फ़ील्ड हैं: name, email, phone, और role (Customer, Manager, Admin). यह छोटा है, लेकिन सामान्य मुद्दे दिखाता है।
क्लाइंट-साइड नियम स्पष्ट होने चाहिए:
- Name: आवश्यक, न्यूनतम लंबाई।
- Email: आवश्यक, वैध ईमेल फॉर्मेट।
- Phone: वैकल्पिक, पर अगर भरा हो तो स्वीकार्य फॉर्मेट से मेल खाना चाहिए।
- Role: आवश्यक, और कभी-कभी कंडीशनल (सिर्फ उन उपयोगकर्ताओं के लिए जिनके पास सही परमिशन हों Admin असाइन कर सकें)।
एक सुसंगत कंपोनेंट कॉन्ट्रैक्ट मददगार है: हर फील्ड को करंट वैल्यू, करंट एरर टेक्स्ट (यदि कोई हो), और कुछ बूलियंस जैसे touched और disabled मिलते हैं। लेबल्स, आवश्यक मार्कर्स, स्पेसिंग, और एरर स्टाइलिंग हर स्क्रीन पर बार-बार नहीं बनाए जाने चाहिए।
अब UX फ्लो। एजेंट ईमेल संपादित करता है, टैब करता है, और अगर फॉर्मेट गलत है तो Email के नीचे इनलाइन संदेश देखता है। वे सुधार करते हैं, Save दबाते हैं, और सर्वर जवाब देता है:
- email already exists: इसे Email के नीचे दिखाएँ और उस फील्ड पर फोकस करें।
- phone invalid: इसे Phone के नीचे दिखाएँ।
- permission denied: एक फॉर्म-लेवल संदेश ऊपर दिखाएँ।
यदि आप एरर्स को फील्ड नाम से की किया हुआ रखते हैं (email, phone, role), तो मैपिंग सरल रहती है। फील्ड एरर्स इनपुट्स के पास land करते हैं, फॉर्म-लेवल एरर्स समर्पित संदेश क्षेत्र में रहते हैं।
सामान्य गलतियाँ और उनसे कैसे बचें
लॉजिक को एक जगह रखें
हर स्क्रीन में वैलिडेशन नियमों की नकल करना तब जल्दी लगता है जब तक नीतियाँ बदल जाती हैं (पासवर्ड नियम, आवश्यक टैक्स ID, अनुमत डोमेन्स)। नियमों को केंद्रीकृत रखें (स्कीमा, नियम फ़ाइल, साझा फ़ंक्शन), और फॉर्म्स उन्हीं नियमों का उपभोग करें।
साथ ही कम-स्तरीय इनपुट्स को बहुत ज़्यादा करना से बचें। यदि आपका <TextField> API को कॉल करना जानता है, फेल पर retry करता है, और सर्वर एरर पेलोड पार्स करता है, तो वह फिर से उपयोग करने योग्य नहीं रहता। फील्ड कंपोनेंट्स केवल रेंडर करें, वैल्यू बदलने को एमिट करें, और त्रुटियाँ दिखाएँ। API कॉल्स और मैपिंग लॉजिक फॉर्म कंटेनर या एक कॉम्बोजेबल में रखें।
लक्षण कि आप कंसर्न्स मिला रहे हैं:
- एक ही वैलिडेशन संदेश कई जगह लिखा गया है।
- कोई फील्ड कंपोनेंट API क्लाइंट इम्पोर्ट करता है।
- एक एंडपॉइंट बदलने से कई असंबंधित फॉर्म्स टूट जाते हैं।
- किसी इनपुट को चेक करने के लिए टेस्टिंग में आधे ऐप को माउंट करना पड़ता है।
UX और एक्सेसिबिलिटी ट्रिपवायर
एक सिंगल एरर बैनर जैसे "Something went wrong" पर्याप्त नहीं है। लोगों को जानना चाहिए कि कौन सा फील्ड गलत है और अगला कदम क्या है। ग्लोबल फेलियर्स (नेटवर्क डाउन, परमिशन डिनायड) के लिए बैनर का उपयोग करें, और सर्वर एरर्स को विशिष्ट इनपुट्स पर मैप करें ताकि उपयोगकर्ता उन्हें जल्दी से सुधार सकें।
लोडिंग और डबल-सबमिट इश्यूज़ भ्रमित कंडीशंस बनाते हैं। सबमिट करते समय सबमिट बटन डिसेबल करें, उन फील्ड्स को डिसेबल करें जिन्हें मिड-सेव बदलना नहीं चाहिए, और एक स्पष्ट बिजी स्टेट दिखाएँ। यह सुनिश्चित करें कि रिसेट और कैंसल फॉर्म को साफ़ रूप से बहाल कर दें।
कस्टम कंपोनेंट्स के साथ एक्सेसिबिलिटी बेसिक्स छोड़ना आसान है। कुछ चुनाव वास्तविक दर्द से बचाते हैं:
- हर इनपुट का एक दृश्यमान लेबल हो (सिर्फ placeholder टेक्स्ट न हो)।
- त्रुटियाँ aria एट्रिब्यूट्स के साथ फील्ड्स से जुड़ी हों।
- सबमिट के बाद फोकस पहले अवैध फील्ड पर जाए।
- डिसेबल्ड फील्ड्स वास्तव में नॉन-इंटरैक्टिव और सही तरीके से announce हों।
- कीबोर्ड नेविगेशन एंड-टू-एंड काम करे।
जल्दी से चेकलिस्ट और अगले कदम
नया फॉर्म शिप करने से पहले एक त्वरित चेकलिस्ट चलाएँ। यह छोटी-छोटी खामियों को पकड़ लेता है जो बाद में सपोर्ट टिकट बन जाती हैं।
- क्या हर फील्ड की स्थिर की वही है जो पेलोड और सर्वर प्रतिक्रिया से मेल खाती है (नेस्टेड पाथ्स जैसे
billing.address.zipसहित)? - क्या आप किसी भी फील्ड को एक सुसंगत फील्ड कंपोनेंट API के साथ रेंडर कर सकते हैं (value इन, events आउट, error और hint इन)?
- सबमिट पर क्या आप एक बार validate करते हैं, डबल सबमिट रोकते हैं, और उपयोगकर्ता को बताने के लिए पहले अवैध फील्ड पर फोकस करते हैं?
- क्या आप त्रुटियाँ सही जगह दिखा सकते हैं: प्रति फील्ड (इनपुट के पास) और फॉर्म लेवल (जब ज़रूरी हो तो सामान्य संदेश)?
- सफलता के बाद क्या आप स्टेट को सही ढंग से रीसेट करते हैं (values, touched, dirty) ताकि अगली एडिट साफ़ शुरू हो?
यदि किसी एक का उत्तर "नहीं" है, तो पहले उसे ठीक करें। सबसे आम फॉर्म दर्द मेल की कमी है: फील्ड नाम API से भटक जाते हैं, या सर्वर त्रुटियाँ ऐसी शेप में लौटती हैं जिसे आपका UI प्लेस नहीं कर सकता।
यदि आप इंटरनल टूल्स बना रहे हैं और तेज़ी से आगे बढना चाहते हैं, तो AppMaster (appmaster.io) वही मूल बातें अपनाता है: फील्ड UI को सुसंगत रखें, नियम और वर्कफ़्लो केंद्रीकृत रखें, और सर्वर प्रतिक्रियाओं को वहां दिखाएँ जहाँ उपयोगकर्ता उन पर कार्रवाई कर सकें।
सामान्य प्रश्न
जब आप विभिन्न पेजों पर एक ही लेबल, हिन्ट, आवश्यक मार्कर, स्पेसिंग और त्रुटि स्टाइल बार-बार देखना शुरू करें, तो उन्हें स्टैण्डर्डाइज़ करें। यदि एक “छोटा” बदलाव कई फाइलें एडिट करने पर मजबूर करता है, तो एक साझा BaseField रैपर और कुछ सुसंगत इनपुट कंपोनेंट्स तेजी से समय बचाएंगे।
फील्ड कंपोनेंट को "डम्ब" रखें: यह लेबल, कंट्रोल, हिन्ट और त्रुटि रेंडर करे और वैल्यू अपडेट्स एमिट करे। क्रॉस-फील्ड लॉजिक, कंडीशनल नियम और अन्य वैल्यूज़ पर निर्भर लॉजिक पैरेंट फॉर्म या वैलिडेशन लेयर में रखें ताकि फील्ड पुन: उपयोग योग्य रहे।
डिफ़ॉल्ट रूप से ऐसे स्थिर कीज़ का उपयोग करें जो आपके API पेलोड से मेल खाती हों, जैसे first_name या billing.address.zip. इससे वैलिडेशन और सर्वर त्रुटि मैपिंग सरल हो जाती है क्योंकि आपको लेयर्स के बीच लगातार नाम अनुवाद नहीं करना पड़ता।
सरल डिफ़ॉल्ट संरचना एक स्टेट ऑब्जेक्ट है जिसमें values, errors, touched, dirty, और defaults हों। जब सब कुछ एक ही शेप के माध्यम से पढ़ता और लिखता है, तो रीसैट और सबमिट व्यवहार अनुमान्य हो जाता है और “आधा-रीसेट” बग्स से बचते हैं।
values और defaults दोनों को एक ही लोड किए गए डेटा से सेट करें। फिर reset() को defaults को values में कॉपी करना चाहिए और touched, dirty, और errors को क्लियर करना चाहिए ताकि UI साफ़ दिखे और सर्वर द्वारा हाल ही में लौटाए गए मान से मेल खाए।
शुरुआत करें उन नियमों से जो सिंपल फ़ंक्शन्स हों और फील्ड नामों की तरह ही की-वर्ड्ड हों। प्रत्येक फील्ड के लिए एक स्पष्ट संदेश (पहली विफलता) लौटाएँ ताकि UI शांत रहे और उपयोगकर्ता जानते हों कि अगला क्या सुधारना है।
अधिकांश फील्ड के लिए ब्लर पर सत्यापन करें, और सबमिट पर सब कुछ एक बार validate करें। ऑन-चेंज वैलिडेशन केवल उन स्थानों पर उपयोग करें जहाँ यह वास्तव में मदद करता है (जैसे पासवर्ड स्ट्रेंथ) ताकि टाइप करते समय उपयोगकर्ताओं को बार-बार त्रुटियों का सामना न करना पड़े।
ऐसिंक चेक्स को ब्लर पर या थोड़े डेबौंस के बाद चलाएँ, और एक स्पष्ट “जाँच कर रहा है...” स्थिति दिखाएँ। धीमी प्रतिक्रियाओं को ओवरराइट करने से रोकने के लिए पुरानी अनुरोधों को रद्द या अनदेखा करें ताकि नए इनपुट पर पुराने परिणाम गलत त्रुटियाँ न दिखाएँ।
हर बैकएंड फ़ॉर्मेट को एक इंटरनल शेप में सामान्यीकृत करें जैसे { fieldErrors: { key: [messages] }, formErrors: [messages] }. एक पाथ स्टाइल (डॉट नोटेशन अच्छा काम करता है) चुनें ताकि address.street हमेशा fieldErrors['address.street'] पढ़ सके बिना स्पेशल केस के।
फ़ॉर्म-लेवल त्रुटियाँ फॉर्म के ऊपर दिखाएँ, पर फील्ड-लेवल त्रुटियाँ ठीक संबंधित इनपुट के पास रखें। फ़ेल होने के बाद पहले उस फील्ड पर फोकस करें जिसकी त्रुटि हो और जब उपयोगकर्ता फील्ड संपादित करे तब उस फील्ड की सर्वर त्रुटि साफ़ कर दें।


