| سمة أو توجيه التحقق | الاستخدام المعماري البرمجي | الأثر الهندسي على حالة الحقل (`Validation Flag`) |
|---|---|---|
| `required` | منع إرسال النموذج أو ترك الحقل فارغاً بأي شكل من الأشكال | يُعيّن حالة الخطأ `errors.required` إذا تركت القيمة فارغة تماماً |
| `minlength / maxlength` | تحديد الحد الأدنى أو الأقصى لعدد المحارف المقبولة في الحقل | يُعيّن حالة الخطأ `errors.minlength` أو `maxlength` عند مخالفة الطول المسموح |
| `pattern` | إلزام المستخدم باتباع تعبير نمطى منتظم (`Regular Expression`) | يُعيّن حالة الخطأ `errors.pattern` إذا لم يتطابق النص المدخل مع النمط الهندسي المطلوب |
يُعد التحقق المدمج من صحة المدخلات (Built-in Form Validation) إحدى أقوى الآليات الجاهزة لتأمين سلامة البيانات مباشرة من خلال سمات الhtml5 المدمجة وتوجيهات أنگولر (مثل required, minlength, maxlength, pattern). يتيح لك هذا النهج فرض قواعد تحقق صارمة دون الحاجة لكتابة دوال برمجية معقدة في صنف الـ TypeScript، مما يسرع عملية التطوير ويحافظ على نظافة المعمارية.
تستفيد النماذج المعتمدة على القوالب في أنگولر من خصائص التحقق الأصلية للمتصفح وتدمجها برمجياً مع حالات أنجولر لتحديث مؤشرات الصلاحية (valid / invalid) لحظياً.
أي تغيير في قيمة الحقل يخضع فوراً للتحقق المدمج، ويتم تعديل كائن الأخطاء control.errors بشكل تلقائي بالكامل لتسهيل اتخاذ القرار البصري في القالب.
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { FormsModule } from '@angular/forms'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-builtin-validation', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule, FormsModule], |
| 9 | template: ` |
| 10 | <div class="validation-demo-card"> |
| 11 | <h3>نموذج التحقق المدمج والقيود المعمارية</h3> |
| 12 | |
| 13 | <form #mainForm="ngForm" (ngSubmit)="processForm(mainForm)"> |
| 14 | |
| 15 | <!-- حقل الكود البرمجي مع قيد الطول والنمط --> |
| 16 | <div class="input-group-wrap"> |
| 17 | <label for="projectCode">كود المشروع (يبدأ بحرفين و4 أرقام):</label> |
| 18 | <input |
| 19 | type="text" |
| 20 | id="projectCode" |
| 21 | name="projectCode" |
| 22 | [(ngModel)]="model.code" |
| 23 | required |
| 24 | pattern="^[A-Z]{2}\\d{4}$" |
| 25 | #codeRef="ngModel" |
| 26 | class="control-input" |
| 27 | [class.invalid-field]="codeRef.invalid && codeRef.touched" |
| 28 | /> |
| 29 | |
| 30 | <div *ngIf="codeRef.invalid && codeRef.touched" class="error-feedback"> |
| 31 | <span *ngIf="codeRef.errors?.['required']">كود المشروع حقل إجباري لا يمكن تجاوزه.</span> |
| 32 | <span *ngIf="codeRef.errors?.['pattern']">الصيغة المدخلة غير صحيحة؛ يجب أن يبدأ بحرفين كبيرين يليهما 4 أرقام.</span> |
| 33 | </div> |
| 34 | </div> |
| 35 | |
| 36 | <!-- حقل القيمة العددية مع حد أدنى وأقصى --> |
| 37 | <div class="input-group-wrap"> |
| 38 | <label for="budget">ميزانية المشروع ($):</label> |
| 39 | <input |
| 40 | type="number" |
| 41 | id="budget" |
| 42 | name="budget" |
| 43 | [(ngModel)]="model.budget" |
| 44 | required |
| 45 | min="1000" |
| 46 | max="50000" |
| 47 | #budgetRef="ngModel" |
| 48 | class="control-input" |
| 49 | [class.invalid-field]="budgetRef.invalid && budgetRef.touched" |
| 50 | /> |
| 51 | |
| 52 | <div *ngIf="budgetRef.invalid && budgetRef.touched" class="error-feedback"> |
| 53 | <span *ngIf="budgetRef.errors?.['required']">ميزانية المشروع مطلوبة.</span> |
| 54 | <span *ngIf="budgetRef.errors?.['min']">الحد الأدنى للميزانية يجب ألا يقل عن 1000 دولار.</span> |
| 55 | <span *ngIf="budgetRef.errors?.['max']">الحد الأقصى للميزانية يجب ألا يتجاوز 50000 دولار.</span> |
| 56 | </div> |
| 57 | </div> |
| 58 | |
| 59 | <button type="submit" [disabled]="mainForm.invalid" class="submit-btn-action"> |
| 60 | اعتماد وإرسال البيانات |
| 61 | </button> |
| 62 | </form> |
| 63 | </div> |
| 64 | `, |
| 65 | styles: [` |
| 66 | .validation-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 20px; } |
| 67 | .input-group-wrap { margin-bottom: 18px; display: flex; flex-direction: column; } |
| 68 | .control-input { background: #1e293b; border: 1px solid #334155; padding: 10px; border-radius: 6px; color: #fff; margin-top: 6px; } |
| 69 | .invalid-field { border-color: #f43f5e !important; } |
| 70 | .error-feedback { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; color: #f43f5e; font-size: 12px; font-weight: bold; } |
| 71 | .submit-btn-action { background: #10b981; color: #090d16; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; width: 100%; } |
| 72 | .submit-btn-action:disabled { background: #475569; cursor: not-allowed; color: #94a3b8; } |
| 73 | `] |
| 74 | }) |
| 75 | export class BuiltinValidationComponent { |
| 76 | model = { |
| 77 | code: '', |
| 78 | budget: null |
| 79 | }; |
| 80 | |
| 81 | processForm(form: any) { |
| 82 | if (form.valid) { |
| 83 | console.log('تم اعتماد النموذج بنجاح عبر أدوات التحقق المدمجة:', this.model); |
| 84 | } |
| 85 | } |
| 86 | } |
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { FormsModule } from '@angular/forms'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-password-match-validation', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule, FormsModule], |
| 9 | template: ` |
| 10 | <div class="validation-demo-card"> |
| 11 | <h3>نموذج مطابقة كلمات المرور والتحقق المدمج</h3> |
| 12 | |
| 13 | <form #passForm="ngForm" class="pass-form-box"> |
| 14 | |
| 15 | <div class="input-group-wrap"> |
| 16 | <label for="newPass">كلمة المرور الجديدة:</label> |
| 17 | <input |
| 18 | type="password" |
| 19 | id="newPass" |
| 20 | name="newPass" |
| 21 | [(ngModel)]="passwords.newPass" |
| 22 | required |
| 23 | minlength="8" |
| 24 | #newPassRef="ngModel" |
| 25 | class="control-input" |
| 26 | /> |
| 27 | </div> |
| 28 | |
| 29 | <div class="input-group-wrap"> |
| 30 | <label for="confirmPass">تأكيد كلمة المرور:</label> |
| 31 | <input |
| 32 | type="password" |
| 33 | id="confirmPass" |
| 34 | name="confirmPass" |
| 35 | [(ngModel)]="passwords.confirmPass" |
| 36 | required |
| 37 | #confirmPassRef="ngModel" |
| 38 | class="control-input" |
| 39 | /> |
| 40 | <div *ngIf="passwords.newPass !== passwords.confirmPass && confirmPassRef.touched" class="error-feedback"> |
| 41 | كلمتا المرور غير متطابقتين! |
| 42 | </div> |
| 43 | </div> |
| 44 | </form> |
| 45 | </div> |
| 46 | `, |
| 47 | styles: [` |
| 48 | .validation-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; } |
| 49 | .input-group-wrap { margin-bottom: 18px; display: flex; flex-direction: column; } |
| 50 | .control-input { background: #1e293b; border: 1px solid #334155; padding: 10px; border-radius: 6px; color: #fff; margin-top: 6px; } |
| 51 | .error-feedback { color: #f43f5e; font-size: 12px; margin-top: 6px; font-weight: bold; } |
| 52 | `] |
| 53 | }) |
| 54 | export class PasswordMatchValidationComponent { |
| 55 | passwords = { |
| 56 | newPass: '', |
| 57 | confirmPass: '' |
| 58 | }; |
| 59 | } |
⚠️ تحذير
لا تعتمد كلياً على التحقق في واجهة المستخدم (Client-side)! أدوات التحقق المدمجة في أنجولر تحسن تجربة الاستخدام بشكل ممتاز، ولكنها تظل حماية بصرية فقط؛ ويجب إملاء قواعد التحقق الصارمة وتأمينها مرة أخرى على مستوى الخادم (Backend API) لحماية أمان النظام بالكامل.