You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ar/7-bank-project/2-forms/README.md

311 lines
24 KiB

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "b667b7d601e2ee19acb5aa9d102dc9f3",
"translation_date": "2025-08-26T00:06:44+00:00",
"source_file": "7-bank-project/2-forms/README.md",
"language_code": "ar"
}
-->
# بناء تطبيق مصرفي الجزء 2: إنشاء نموذج تسجيل دخول وتسجيل حساب
## اختبار ما قبل المحاضرة
[اختبار ما قبل المحاضرة](https://ff-quizzes.netlify.app/web/quiz/43)
### المقدمة
في معظم تطبيقات الويب الحديثة، يمكنك إنشاء حساب للحصول على مساحة خاصة بك. نظرًا لأن العديد من المستخدمين يمكنهم الوصول إلى تطبيق ويب في نفس الوقت، تحتاج إلى آلية لتخزين بيانات كل مستخدم بشكل منفصل وتحديد المعلومات التي سيتم عرضها. لن نتناول كيفية إدارة [هوية المستخدم بشكل آمن](https://en.wikipedia.org/wiki/Authentication) لأنها موضوع واسع بحد ذاته، ولكننا سنتأكد من أن كل مستخدم يمكنه إنشاء حساب بنكي واحد (أو أكثر) في تطبيقنا.
في هذا الجزء، سنستخدم نماذج HTML لإضافة تسجيل الدخول والتسجيل إلى تطبيق الويب الخاص بنا. سنرى كيفية إرسال البيانات إلى واجهة برمجة التطبيقات للخادم برمجيًا، وأخيرًا كيفية تحديد قواعد التحقق الأساسية لإدخالات المستخدم.
### المتطلبات الأساسية
يجب أن تكون قد أكملت [قوالب HTML والتوجيه](../1-template-route/README.md) لتطبيق الويب لهذه الدرسة. كما تحتاج إلى تثبيت [Node.js](https://nodejs.org) وتشغيل [واجهة برمجة التطبيقات للخادم](../api/README.md) محليًا حتى تتمكن من إرسال البيانات لإنشاء الحسابات.
**ملاحظة مهمة**
ستحتاج إلى تشغيل نافذتي طرفية في نفس الوقت كما هو موضح أدناه:
1. لتطبيق البنك الرئيسي الذي قمنا ببنائه في درس [قوالب HTML والتوجيه](../1-template-route/README.md).
2. لواجهة برمجة التطبيقات للخادم [Bank APP server API](../api/README.md) التي قمنا بإعدادها أعلاه.
يجب أن يكون كلا الخادمين قيد التشغيل لمتابعة بقية الدرس. يتم الاستماع على منافذ مختلفة (المنفذ `3000` والمنفذ `5000`) لذا يجب أن يعمل كل شيء بشكل جيد.
يمكنك اختبار أن الخادم يعمل بشكل صحيح عن طريق تنفيذ هذا الأمر في نافذة طرفية:
```sh
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
```
---
## النماذج وعناصر التحكم
عنصر `<form>` يضم قسمًا من مستند HTML حيث يمكن للمستخدم إدخال البيانات وإرسالها باستخدام عناصر تحكم تفاعلية. هناك جميع أنواع عناصر واجهة المستخدم (UI) التي يمكن استخدامها داخل النموذج، وأكثرها شيوعًا هما عنصرا `<input>` و`<button>`.
هناك العديد من [الأنواع](https://developer.mozilla.org/docs/Web/HTML/Element/input) المختلفة من `<input>`، على سبيل المثال لإنشاء حقل حيث يمكن للمستخدم إدخال اسم المستخدم الخاص به يمكنك استخدام:
```html
<input id="username" name="username" type="text">
```
سوف يتم استخدام خاصية `name` كاسم الخاصية عند إرسال بيانات النموذج. يتم استخدام خاصية `id` لربط `<label>` بعنصر التحكم في النموذج.
> ألقِ نظرة على القائمة الكاملة لأنواع [`<input>`](https://developer.mozilla.org/docs/Web/HTML/Element/input) و[عناصر التحكم الأخرى في النماذج](https://developer.mozilla.org/docs/Learn/Forms/Other_form_controls) للحصول على فكرة عن جميع عناصر واجهة المستخدم الأصلية التي يمكنك استخدامها عند بناء واجهتك.
✅ لاحظ أن `<input>` هو [عنصر فارغ](https://developer.mozilla.org/docs/Glossary/Empty_element) لا يجب أن تضيف له علامة إغلاق مطابقة. يمكنك مع ذلك استخدام صيغة الإغلاق الذاتي `<input/>`، ولكنها ليست مطلوبة.
عنصر `<button>` داخل النموذج له سلوك خاص. إذا لم تحدد خاصية `type`، فسيقوم تلقائيًا بإرسال بيانات النموذج إلى الخادم عند الضغط عليه. فيما يلي القيم الممكنة لـ `type`:
- `submit`: القيمة الافتراضية داخل `<form>`، الزر يقوم بتشغيل إجراء إرسال النموذج.
- `reset`: الزر يعيد جميع عناصر التحكم في النموذج إلى قيمها الأولية.
- `button`: لا يتم تعيين سلوك افتراضي عند الضغط على الزر. يمكنك بعد ذلك تعيين إجراءات مخصصة له باستخدام JavaScript.
### المهمة
لنبدأ بإضافة نموذج إلى قالب `login`. سنحتاج إلى حقل *اسم المستخدم* وزر *تسجيل الدخول*.
```html
<template id="login">
<h1>Bank App</h1>
<section>
<h2>Login</h2>
<form id="loginForm">
<label for="username">Username</label>
<input id="username" name="user" type="text">
<button>Login</button>
</form>
</section>
</template>
```
إذا نظرت عن كثب، يمكنك ملاحظة أننا أضفنا أيضًا عنصر `<label>` هنا. يتم استخدام عناصر `<label>` لإضافة اسم لعناصر واجهة المستخدم، مثل حقل اسم المستخدم الخاص بنا. التسميات مهمة لقراءة النماذج الخاصة بك، ولكنها تأتي أيضًا بفوائد إضافية:
- من خلال ربط التسمية بعنصر التحكم في النموذج، فإنها تساعد المستخدمين الذين يستخدمون تقنيات مساعدة (مثل قارئ الشاشة) على فهم البيانات التي يُتوقع منهم تقديمها.
- يمكنك النقر على التسمية لوضع التركيز مباشرة على الإدخال المرتبط، مما يجعل الوصول إليه أسهل على الأجهزة التي تعمل باللمس.
> [إمكانية الوصول](https://developer.mozilla.org/docs/Learn/Accessibility/What_is_accessibility) على الويب موضوع مهم غالبًا ما يتم تجاهله. بفضل [عناصر HTML الدلالية](https://developer.mozilla.org/docs/Learn/Accessibility/HTML) ليس من الصعب إنشاء محتوى يمكن الوصول إليه إذا استخدمتها بشكل صحيح. يمكنك [قراءة المزيد عن إمكانية الوصول](https://developer.mozilla.org/docs/Web/Accessibility) لتجنب الأخطاء الشائعة وتصبح مطورًا مسؤولًا.
الآن سنضيف نموذجًا ثانيًا للتسجيل، أسفل النموذج السابق مباشرة:
```html
<hr/>
<h2>Register</h2>
<form id="registerForm">
<label for="user">Username</label>
<input id="user" name="user" type="text">
<label for="currency">Currency</label>
<input id="currency" name="currency" type="text" value="$">
<label for="description">Description</label>
<input id="description" name="description" type="text">
<label for="balance">Current balance</label>
<input id="balance" name="balance" type="number" value="0">
<button>Register</button>
</form>
```
باستخدام خاصية `value` يمكننا تحديد قيمة افتراضية لإدخال معين.
لاحظ أيضًا أن الإدخال الخاص بـ `balance` يحتوي على النوع `number`. هل يبدو مختلفًا عن الإدخالات الأخرى؟ حاول التفاعل معه.
✅ هل يمكنك التنقل والتفاعل مع النماذج باستخدام لوحة المفاتيح فقط؟ كيف يمكنك القيام بذلك؟
## إرسال البيانات إلى الخادم
الآن بعد أن أصبح لدينا واجهة مستخدم وظيفية، الخطوة التالية هي إرسال البيانات إلى الخادم. دعنا نجري اختبارًا سريعًا باستخدام الكود الحالي: ماذا يحدث إذا نقرت على زر *تسجيل الدخول* أو *التسجيل*؟
هل لاحظت التغيير في قسم عنوان URL في المتصفح؟
![لقطة شاشة لتغيير عنوان URL في المتصفح بعد النقر على زر التسجيل](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.ar.png)
الإجراء الافتراضي لـ `<form>` هو إرسال النموذج إلى عنوان URL الحالي للخادم باستخدام [طريقة GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3)، مع إلحاق بيانات النموذج مباشرة بعنوان URL. ومع ذلك، لهذه الطريقة بعض العيوب:
- البيانات المرسلة محدودة الحجم (حوالي 2000 حرف).
- البيانات مرئية مباشرة في عنوان URL (وهذا ليس جيدًا لكلمات المرور).
- لا تعمل مع تحميل الملفات.
لهذا السبب يمكنك تغييرها لاستخدام [طريقة POST](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) التي ترسل بيانات النموذج إلى الخادم في جسم طلب HTTP، دون أي من القيود السابقة.
> بينما تُعد POST الطريقة الأكثر استخدامًا لإرسال البيانات، [في بعض السيناريوهات المحددة](https://www.w3.org/2001/tag/doc/whenToUseGet.html) يُفضل استخدام طريقة GET، عند تنفيذ حقل بحث على سبيل المثال.
### المهمة
أضف خصائص `action` و`method` إلى نموذج التسجيل:
```html
<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">
```
حاول الآن تسجيل حساب جديد باسمك. بعد النقر على زر *التسجيل*، يجب أن ترى شيئًا مثل هذا:
![نافذة متصفح على العنوان localhost:5000/api/accounts، تعرض سلسلة JSON تحتوي على بيانات المستخدم](../../../../translated_images/form-post.61de4ca1b964d91a9e338416e19f218504dd0af5f762fbebabfe7ae80edf885f.ar.png)
إذا سار كل شيء على ما يرام، يجب أن يجيب الخادم على طلبك باستجابة [JSON](https://www.json.org/json-en.html) تحتوي على بيانات الحساب التي تم إنشاؤها.
✅ حاول التسجيل مرة أخرى بنفس الاسم. ماذا يحدث؟
## إرسال البيانات دون إعادة تحميل الصفحة
كما لاحظت على الأرجح، هناك مشكلة بسيطة في النهج الذي استخدمناه للتو: عند إرسال النموذج، نخرج من تطبيقنا ويعيد المتصفح التوجيه إلى عنوان URL الخاص بالخادم. نحن نحاول تجنب جميع عمليات إعادة تحميل الصفحة مع تطبيق الويب الخاص بنا، حيث نقوم بإنشاء [تطبيق صفحة واحدة (SPA)](https://en.wikipedia.org/wiki/Single-page_application).
لإرسال بيانات النموذج إلى الخادم دون فرض إعادة تحميل الصفحة، علينا استخدام كود JavaScript. بدلاً من وضع عنوان URL في خاصية `action` لعنصر `<form>`، يمكنك استخدام أي كود JavaScript مسبوقًا بالسلسلة `javascript:` لتنفيذ إجراء مخصص. باستخدام هذا، يعني أنك ستحتاج إلى تنفيذ بعض المهام التي كانت تتم تلقائيًا بواسطة المتصفح:
- استرداد بيانات النموذج.
- تحويل وترميز بيانات النموذج إلى تنسيق مناسب.
- إنشاء طلب HTTP وإرساله إلى الخادم.
### المهمة
استبدل خاصية `action` لنموذج التسجيل بـ:
```html
<form id="registerForm" action="javascript:register()">
```
افتح `app.js` وأضف وظيفة جديدة باسم `register`:
```js
function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const data = Object.fromEntries(formData);
const jsonData = JSON.stringify(data);
}
```
هنا نسترد عنصر النموذج باستخدام `getElementById()` ونستخدم أداة [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData) لاستخراج القيم من عناصر التحكم في النموذج كمجموعة من أزواج المفتاح/القيمة. ثم نحول البيانات إلى كائن عادي باستخدام [`Object.fromEntries()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) وأخيرًا نقوم بتسلسل البيانات إلى [JSON](https://www.json.org/json-en.html)، وهو تنسيق شائع الاستخدام لتبادل البيانات على الويب.
البيانات الآن جاهزة للإرسال إلى الخادم. قم بإنشاء وظيفة جديدة باسم `createAccount`:
```js
async function createAccount(account) {
try {
const response = await fetch('//localhost:5000/api/accounts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: account
});
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
```
ماذا تفعل هذه الوظيفة؟ أولاً، لاحظ الكلمة الرئيسية `async` هنا. هذا يعني أن الوظيفة تحتوي على كود سيتم تنفيذه [**بشكل غير متزامن**](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function). عند استخدامها مع الكلمة الرئيسية `await`، فإنها تسمح بالانتظار حتى يتم تنفيذ الكود غير المتزامن - مثل انتظار استجابة الخادم هنا - قبل المتابعة.
إليك فيديو سريع عن استخدام `async/await`:
[![Async and Await لإدارة الوعود](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "Async and Await لإدارة الوعود")
> 🎥 انقر على الصورة أعلاه لمشاهدة فيديو عن async/await.
نستخدم واجهة `fetch()` لإرسال بيانات JSON إلى الخادم. تأخذ هذه الطريقة معلمتين:
- عنوان URL الخاص بالخادم، لذا نضع هنا `//localhost:5000/api/accounts`.
- إعدادات الطلب. هنا نحدد الطريقة بـ `POST` ونوفر `body` للطلب. بما أننا نرسل بيانات JSON إلى الخادم، نحتاج أيضًا إلى تعيين رأس `Content-Type` إلى `application/json` حتى يعرف الخادم كيفية تفسير المحتوى.
بما أن الخادم سيرد على الطلب بـ JSON، يمكننا استخدام `await response.json()` لتحليل محتوى JSON وإرجاع الكائن الناتج. لاحظ أن هذه الطريقة غير متزامنة، لذا نستخدم الكلمة الرئيسية `await` هنا قبل الإرجاع للتأكد من أن أي أخطاء أثناء التحليل يتم التقاطها أيضًا.
الآن أضف بعض الكود إلى وظيفة `register` لاستدعاء `createAccount()`:
```js
const result = await createAccount(jsonData);
```
بما أننا نستخدم الكلمة الرئيسية `await` هنا، نحتاج إلى إضافة الكلمة الرئيسية `async` قبل وظيفة register:
```js
async function register() {
```
أخيرًا، دعنا نضيف بعض السجلات للتحقق من النتيجة. يجب أن تبدو الوظيفة النهائية كما يلي:
```js
async function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const jsonData = JSON.stringify(Object.fromEntries(formData));
const result = await createAccount(jsonData);
if (result.error) {
return console.log('An error occurred:', result.error);
}
console.log('Account created!', result);
}
```
كان ذلك طويلاً بعض الشيء ولكننا وصلنا! إذا فتحت [أدوات مطوري المتصفح](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools)، وحاولت تسجيل حساب جديد، يجب ألا ترى أي تغيير على صفحة الويب ولكن ستظهر رسالة في وحدة التحكم تؤكد أن كل شيء يعمل.
![لقطة شاشة تظهر رسالة سجل في وحدة تحكم المتصفح](../../../../translated_images/browser-console.efaf0b51aaaf67782a29e1a0bb32cc063f189b18e894eb5926e02f1abe864ec2.ar.png)
✅ هل تعتقد أن البيانات يتم إرسالها إلى الخادم بشكل آمن؟ ماذا لو تمكن شخص ما من اعتراض الطلب؟ يمكنك قراءة المزيد عن [HTTPS](https://en.wikipedia.org/wiki/HTTPS) لمعرفة المزيد عن الاتصال الآمن للبيانات.
## التحقق من البيانات
إذا حاولت تسجيل حساب جديد دون تعيين اسم مستخدم أولاً، يمكنك رؤية أن الخادم يعيد خطأ برمز الحالة [400 (طلب غير صالح)](https://developer.mozilla.org/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).).
قبل إرسال البيانات إلى الخادم، من الجيد [التحقق من بيانات النموذج](https://developer.mozilla.org/docs/Learn/Forms/Form_validation) مسبقًا عند الإمكان، للتأكد من أنك ترسل طلبًا صالحًا. توفر عناصر التحكم في نماذج HTML5 التحقق المدمج باستخدام سمات مختلفة:
- `required`: يجب ملء الحقل وإلا لا يمكن إرسال النموذج.
- `minlength` و`maxlength`: تحدد الحد الأدنى والأقصى لعدد الأحرف في الحقول النصية.
- `min` و`max`: تحدد الحد الأدنى والأقصى لقيمة الحقل الرقمي.
- `type`: تحدد نوع البيانات المتوقع، مثل `number`، `email`، `file` أو [أنواع مدمجة أخرى](https://developer.mozilla.org/docs/Web/HTML/Element/input). قد يغير هذا السمة أيضًا العرض المرئي لعنصر التحكم في النموذج.
- `pattern`: يسمح بتحديد [تعبير منتظم](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Regular_Expressions) لاختبار ما إذا كانت البيانات المدخلة صالحة أم لا.
يمكنك تخصيص مظهر عناصر التحكم في النموذج الخاص بك بناءً على كونها صحيحة أم لا باستخدام الفئات الزائفة CSS `:valid` و `:invalid`.
### المهمة
هناك حقلان مطلوبان لإنشاء حساب جديد صالح، وهما اسم المستخدم والعملة، بينما تكون الحقول الأخرى اختيارية. قم بتحديث HTML الخاص بالنموذج باستخدام كل من السمة `required` والنص في تسمية الحقل بحيث:
```html
<label for="user">Username (required)</label>
<input id="user" name="user" type="text" required>
...
<label for="currency">Currency (required)</label>
<input id="currency" name="currency" type="text" value="$" required>
```
على الرغم من أن تنفيذ الخادم هذا لا يفرض حدودًا محددة على الحد الأقصى لطول الحقول، إلا أنه من الجيد دائمًا تحديد حدود معقولة لأي إدخال نصي من المستخدم.
أضف سمة `maxlength` إلى حقول النص:
```html
<input id="user" name="user" type="text" maxlength="20" required>
...
<input id="currency" name="currency" type="text" value="$" maxlength="5" required>
...
<input id="description" name="description" type="text" maxlength="100">
```
الآن إذا ضغطت على زر *تسجيل* وكان هناك حقل لا يحترم قاعدة التحقق التي قمنا بتعريفها، يجب أن ترى شيئًا مثل هذا:
![لقطة شاشة تظهر خطأ التحقق عند محاولة إرسال النموذج](../../../../translated_images/validation-error.8bd23e98d416c22f80076d04829a4bb718e0e550fd622862ef59008ccf0d5dce.ar.png)
التحقق مثل هذا الذي يتم *قبل* إرسال أي بيانات إلى الخادم يسمى **التحقق من جانب العميل**. ولكن لاحظ أنه ليس من الممكن دائمًا إجراء جميع الفحوصات دون إرسال البيانات. على سبيل المثال، لا يمكننا التحقق هنا مما إذا كان هناك حساب موجود بالفعل بنفس اسم المستخدم دون إرسال طلب إلى الخادم. يتم إجراء التحقق الإضافي على الخادم ويُسمى **التحقق من جانب الخادم**.
عادةً ما يتم تنفيذ كلا النوعين، وبينما يحسن استخدام التحقق من جانب العميل تجربة المستخدم من خلال تقديم ملاحظات فورية، فإن التحقق من جانب الخادم ضروري لضمان أن البيانات التي تتعامل معها آمنة وسليمة.
---
## 🚀 التحدي
اعرض رسالة خطأ في HTML إذا كان المستخدم موجودًا بالفعل.
إليك مثالًا على الشكل النهائي لصفحة تسجيل الدخول بعد إضافة بعض التنسيقات:
![لقطة شاشة لصفحة تسجيل الدخول بعد إضافة أنماط CSS](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.ar.png)
## اختبار ما بعد المحاضرة
[اختبار ما بعد المحاضرة](https://ff-quizzes.netlify.app/web/quiz/44)
## المراجعة والدراسة الذاتية
أصبح المطورون مبدعين للغاية في جهودهم لبناء النماذج، خاصة فيما يتعلق باستراتيجيات التحقق. تعرف على تدفقات النماذج المختلفة من خلال تصفح [CodePen](https://codepen.com)؛ هل يمكنك العثور على نماذج مثيرة وملهمة؟
## الواجب
[قم بتنسيق تطبيق البنك الخاص بك](assignment.md)
**إخلاء المسؤولية**:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.