
لإنشاء واجهة سهلة الاستخدام ، تحتاج إلى التأكد من أن جميع النماذج في التطبيق الخاص بك تعمل باستمرار. غالبًا ما يتحقق السلوك الرتيب عن طريق التعليمات البرمجية المتكررة ، وإن كان ذلك ضمنيًا. اسمحوا لي أن أشارك رسمًا تخطيطيًا لنمط أعتقد أنه يبسط التطوير ويوحد سلوك النموذج.
إذا كان رمز إرسال النماذج في مشروعك مشابهًا لهذا ، أنصحك بالبحث تحت cat.
onSubmit (): باطل
// login.component.ts
// bad practices
onSubmit(): void {
this.formSubmitted = true;
this.isUnhandledServerError = false;
if (!this.formGroup.valid) return;
this.isLoading = true;
const { username, password } = this.formGroup.value;
this.login(username, password)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({ error: error => this.handleError(error) });
}
بالنسبة لأولئك الذين يحبون الكود فقط: قم
بالمشروع على stackblitz قبل إعادة البناء.
مشروع Stackblitz بعد إعادة البناء.
وصف المشكلة
تتطلب النماذج العديد من الفروق الدقيقة التي يجب مراعاتها. من وجهة نظر وظيفية ، يرسل النموذج فقط المعلومات التي أدخلها المستخدم إلى الخادم. ولكن لضمان جودة تجربة المستخدم ، بالإضافة إلى كل شيء ، عليك إجراء التحقق من الصحة وعرض الأخطاء من الخادم ومؤشر التحميل وما إلى ذلك. من الناحية العملية ، غالبًا ما يتجاهل المطورون هذه التفاصيل ، مما يؤثر سلبًا على قابلية استخدام التطبيق ، أو يؤدي إلى تكرار الكود ويجعل تطوير النموذج أمرًا لا يطاق.
في ما يلي مثال على معالج إرسال نموذج جيد من وجهة نظر UX ، ولكنه سيء من وجهة نظر التطوير. مشروع Stackblitz قبل إعادة البناء.
// login.component.ts
onSubmit(): void {
this.formSubmitted = true; //
this.isUnhandledServerError = false; //
if (!this.formGroup.valid) return; //
this.isLoading = true; //
const { username, password } = this.formGroup.value;
this.login(username, password) //
.pipe(finalize(() => (this.isLoading = false))) //
.subscribe({ error: error => this.handleError(error) });
}
كما ترى ، يأخذ هذا المعالج في الاعتبار الكثير من التفاصيل التي تشكل UX. المشكلة الوحيدة هي أنه مع هذا النهج ، يجب كتابة هذه الفروق الدقيقة لكل نموذج في التطبيق.
القرار
لتبسيط التطوير وتوحيد سلوك النماذج في التطبيق الخاص بك ، تحتاج إلى نقل رمز معالج إرسال النموذج إلى فئة منفصلة. مشروع Stackblitz بعد إعادة البناء. (لقد قمت عن قصد بتبسيط الكود على سبيل المثال ، في مشروع حقيقي تحتاج إلى استبدال جميع الحقول المنطقية بـ Observable.)
class Form<T> {
submitted = false;
pending = false;
hasUnhandledServerError = false;
constructor(private formGroup: FormGroup, private action: (value: any) => Observable<T>) {}
submit(): Observable<T> {
if (this.pending) return EMPTY;
this.submitted = true;
this.hasUnhandledServerError = false;
if (this.formGroup.valid) {
this.pending = true;
return this.action(this.formGroup.value).pipe(
tap({ error: () => (this.hasUnhandledServerError = true) }),
finalize(() => (this.pending = false)),
);
}
return EMPTY;
}
}
وبالتالي ، فإننا نركز معظم ميزات UX في فئة واحدة ونتخلص من المنطق المكرر. الآن ستستغرق كتابة نموذج جديد وقتًا أقل ، ويمكنك إكمال سلوك النماذج في جميع أنحاء التطبيق عن طريق تغيير فئة النموذج فقط.
لماذا لا تضعه في المكتبة؟
تعتبر متطلبات تجربة المستخدم لكل مشروع فريدة وتعتمد بشكل أكبر على المصمم. كان علي بالفعل تجاوز سلوك عناصر المواد القياسية بناءً على طلب العميل. لذلك ، لا أرى أي طريقة لتوحيد سلوك النماذج في جميع التطبيقات باستخدام مكتبة واحدة. دع سلوك الواجهة يظل تحت رحمة المصمم والمطورين. ومع ذلك ، أعتقد أنه من الجيد فصل المنطق المتعلق بتجربة المستخدم إلى فئات منفصلة.
آمل أن يكون المثال مفيدًا وستحاول استخدام الفكرة في مشاريعك. في حين!