| طريقة التعامل البرمجية | التعبير المستخدم في القالب | الأثر الهندسي على تدفق البيانات |
|---|---|---|
| ربط حدث الإرسال | `(ngSubmit)="onSubmit(formRef)"` | منع التحديث الافتراضي للصفحة (`Prevent Default`) وتوجيه البيانات لدالة المعالجة بأمان |
| استخراج قيم الحقول بالكامل | `formRef.value` | الحصول على كائن جافاسكريبت متكامل يحمل أسماء الحقول وقيمها المدخلة مباشرة |
| التحقق من الصلاحية الإجمالية | `if (formRef.valid)` | حظر تنفيذ كود الإرسال إذا كان هناك أي حقل مخالف لشروط وقواعد التحقق الهندسية |
يمثل التعامل مع أحداث الإرسال وقراءة بيانات النموذج (Handling Form Submission and Reading Data) المحطة النهائية والحرجة لربط واجهة المستخدم بالمنطق البرمجي. باستخدام توجيه ربط الحدث (ngSubmit) مع تمرير مرجع النموذج المحلي، يمكنك استخلاص البيانات المدخلة وتنظيمها بدقة تامة لضمان إرسال كائن نظيف وموثوق للخادم (Backend).
يُفضل استخدام (ngSubmit) على عنصر <form> بدلاً من استخدام (click) على زر الإرسال؛ لأن ngSubmit يستجيب تلقائياً لعملية الضغط على مفتاح الإدخال (Enter) داخل أي حقل من حقول النموذج، مما يحسن تجربة المستخدم.
عبر تعريف مرجع مثل #formRef="ngForm" وتمريره لدالة المعالجة في صنف الـ TypeScript، يمكنك الوصول الفوري إلى قيم النموذج (formRef.value) وحالته (formRef.valid) دون الحاجة لتعقيدات البرمجة الحتمية.
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { FormsModule } from '@angular/forms'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-form-submission-demo', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule, FormsModule], |
| 9 | template: ` |
| 10 | <div class="submission-card-demo"> |
| 11 | <h3>إدارة أحداث الإرسال وقراءة بيانات النموذج</h3> |
| 12 | |
| 13 | <!-- ربط حدث الإرسال ومعالجة النموذج عبر مرجع محلي --> |
| 14 | <form #orderForm="ngForm" (ngSubmit)="handleFormSubmit(orderForm)"> |
| 15 | |
| 16 | <div class="input-block"> |
| 17 | <label for="clientName">اسم العميل:</label> |
| 18 | <input |
| 19 | type="text" |
| 20 | id="clientName" |
| 21 | name="clientName" |
| 22 | [(ngModel)]="orderData.clientName" |
| 23 | required |
| 24 | #clientRef="ngModel" |
| 25 | class="styled-input" |
| 26 | [class.error-border]="clientRef.invalid && clientRef.touched" |
| 27 | /> |
| 28 | <div *ngIf="clientRef.invalid && clientRef.touched" class="error-text"> |
| 29 | اسم العميل مطلوب ولا يمكن ترك الحقل فارغاً. |
| 30 | </div> |
| 31 | </div> |
| 32 | |
| 33 | <div class="input-block"> |
| 34 | <label for="orderAmount">قيمة الطلب ($):</label> |
| 35 | <input |
| 36 | type="number" |
| 37 | id="orderAmount" |
| 38 | name="orderAmount" |
| 39 | [(ngModel)]="orderData.orderAmount" |
| 40 | required |
| 41 | min="10" |
| 42 | #amountRef="ngModel" |
| 43 | class="styled-input" |
| 44 | [class.error-border]="amountRef.invalid && amountRef.touched" |
| 45 | /> |
| 46 | <div *ngIf="amountRef.invalid && amountRef.touched" class="error-text"> |
| 47 | يجب إدخال قيمة طلب صحيحة لا تقل عن 10 دولارات. |
| 48 | </div> |
| 49 | </div> |
| 50 | |
| 51 | <!-- زر الإرسال المشروط بصلاحية النموذج --> |
| 52 | <button type="submit" [disabled]="orderForm.invalid" class="submit-action-btn"> |
| 53 | حفظ وإرسال بيانات الطلب |
| 54 | </button> |
| 55 | </form> |
| 56 | |
| 57 | <!-- عرض البيانات المستخرجة بنجاح للتأكيد --> |
| 58 | <div *ngIf="submittedData" class="result-display-box"> |
| 59 | <h4>تم استخراج البيانات بنجاح:</h4> |
| 60 | <pre>{{ submittedData | json }}</pre> |
| 61 | </div> |
| 62 | </div> |
| 63 | `, |
| 64 | styles: [` |
| 65 | .submission-card-demo { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 20px; } |
| 66 | .input-block { margin-bottom: 18px; display: flex; flex-direction: column; } |
| 67 | .styled-input { background: #1e293b; border: 1px solid #334155; padding: 10px; border-radius: 6px; color: #fff; margin-top: 6px; } |
| 68 | .error-border { border-color: #f43f5e !important; } |
| 69 | .error-text { color: #f43f5e; font-size: 12px; margin-top: 4px; font-weight: bold; } |
| 70 | .submit-action-btn { background: #10b981; color: #090d16; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; width: 100%; } |
| 71 | .submit-action-btn:disabled { background: #475569; cursor: not-allowed; color: #94a3b8; } |
| 72 | .result-display-box { background: #1e293b; border: 1px solid #334155; padding: 16px; border-radius: 8px; margin-top: 20px; } |
| 73 | .result-display-box pre { color: #38bdf8; font-size: 13px; margin: 0; } |
| 74 | `] |
| 75 | }) |
| 76 | export class FormSubmissionDemoComponent { |
| 77 | orderData = { |
| 78 | clientName: '', |
| 79 | orderAmount: null |
| 80 | }; |
| 81 | |
| 82 | submittedData: any = null; |
| 83 | |
| 84 | handleFormSubmit(form: any) { |
| 85 | if (form.valid) { |
| 86 | // قراءة واستخراج البيانات مباشرة من كائن النموذج البرمجي |
| 87 | this.submittedData = form.value; |
| 88 | console.log('بيانات النموذج المستخرجة عند الحفظ:', this.submittedData); |
| 89 | } |
| 90 | } |
| 91 | } |
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { FormsModule } from '@angular/forms'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-form-reset-action', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule, FormsModule], |
| 9 | template: ` |
| 10 | <div class="submission-card-demo"> |
| 11 | <h3>نموذج معالجة الحفظ مع إعادة التعيين المعماري</h3> |
| 12 | |
| 13 | <form #resetForm="ngForm" (ngSubmit)="onSaveAndReset(resetForm)"> |
| 14 | |
| 15 | <div class="input-block"> |
| 16 | <label for="feedbackText">ملاحظات النظام:</label> |
| 17 | <textarea |
| 18 | id="feedbackText" |
| 19 | name="feedbackText" |
| 20 | [(ngModel)]="feedback" |
| 21 | required |
| 22 | class="styled-textarea" |
| 23 | ></textarea> |
| 24 | </div> |
| 25 | |
| 26 | <button type="submit" [disabled]="resetForm.invalid" class="submit-action-btn"> |
| 27 | حفظ وتفريغ النموذج |
| 28 | </button> |
| 29 | </form> |
| 30 | </div> |
| 31 | `, |
| 32 | styles: [` |
| 33 | .submission-card-demo { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; } |
| 34 | .input-block { margin-bottom: 18px; display: flex; flex-direction: column; } |
| 35 | .styled-textarea { background: #1e293b; border: 1px solid #334155; padding: 10px; border-radius: 6px; color: #fff; margin-top: 6px; height: 80px; resize: none; } |
| 36 | .submit-action-btn { background: #38bdf8; color: #090d16; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; width: 100%; } |
| 37 | .submit-action-btn:disabled { background: #475569; cursor: not-allowed; color: #94a3b8; } |
| 38 | `] |
| 39 | }) |
| 40 | export class FormResetActionComponent { |
| 41 | feedback = ''; |
| 42 | |
| 43 | onSaveAndReset(form: any) { |
| 44 | if (form.valid) { |
| 45 | console.log('تم حفظ الملاحظات:', form.value); |
| 46 | |
| 47 | // إعادة تعيين النموذج بالكامل وإرجاع الحقول لحالتها الأصلية غير المُلمسة |
| 48 | form.resetForm(); |
| 49 | } |
| 50 | } |
| 51 | } |