7. تحويل تطبيق إلى Ajax ASP.NET MVC
7.1. مكانة AJAX في تطبيق ويب
في الوقت الحالي، تتميز أمثلة التعلم التي تمت دراستها بالبنية التالية:
![]() |
للانتقال من عرض [Vue1] إلى عرض [Vue2]، يقوم المتصفح بما يلي:
- يرسل طلبًا إلى تطبيق الويب؛
- يتلقى العرض [Vue2] ويعرضه بدلاً من العرض [Vue1].
هذا هو المخطط الكلاسيكي:
- طلب من المتصفح؛
- إعداد عرض كاستجابة للعميل بواسطة خادم الويب؛
- عرض هذه العرض الجديد بواسطة المتصفح.
هناك طريقة أخرى للتفاعل بين المتصفح وخادم الويب: AJAX (Asynchronous Javascript And Xml). يتعلق الأمر في الواقع بتفاعلات بين العرض الذي يعرضه المتصفح وخادم الويب. يستمر المتصفح في القيام بما يجيده، وهو عرض عرض HTML، ولكنه أصبح الآن يخضع للتحكم بواسطة جافا سكريبت مدمج في العرض HTML المعروض. المخطط هو كما يلي:
![]() |
- في [1]، يحدث حدث في الصفحة المعروضة في المتصفح (النقر على زر، تغيير نص، ...). يتم اعتراض هذا الحدث بواسطة جافا سكريبت (JS) مدمج في الصفحة؛
- في [2]، يقوم كود جافا سكريبت بإرسال طلب HTTP كما كان سيفعل المتصفح. الطلب غير متزامن: يمكن للمستخدم الاستمرار في التفاعل مع الصفحة دون أن يتعطل بسبب انتظار الرد على الطلب HTTP. يتبع الطلب عملية المعالجة التقليدية. لا شيء (أو القليل) يميزه عن الطلب التقليدي؛
- في [3]، يتم إرسال استجابة إلى العميل JS. بدلاً من عرض HTML الكامل، يتم إرسال عرض HTML الجزئي، أو تدفق XML أو JSON (JavaScript Object Notation)؛
- في [4]، يسترد جافا سكريبت هذا الرد ويستخدمه لتحديث منطقة من الصفحة المعروضة HTML.
بالنسبة للمستخدم، يحدث تغيير في العرض لأن ما يراه قد تغير. ومع ذلك، لا يتم إعادة تحميل الصفحة بالكامل، بل مجرد تعديل جزئي للصفحة المعروضة. وهذا يساهم في إضفاء السلاسة والتفاعلية على الصفحة: نظرًا لعدم إعادة تحميل الصفحة بالكامل، يمكننا إدارة أحداث لم نكن نديرها من قبل. على سبيل المثال، تقديم قائمة خيارات للمستخدم أثناء قيامه بكتابة الأحرف في مربع الإدخال. مع كل حرف جديد يتم كتابته، يتم إرسال طلب AJAX إلى الخادم الذي يرسل بدوره اقتراحات أخرى. بدون Ajax، كان هذا النوع من المساعدة في الكتابة مستحيلًا في السابق. لم يكن من الممكن إعادة تحميل صفحة جديدة مع كل حرف يتم كتابته.
7.2. أساسيات JQuery و Javascript
غالبًا ما قمنا بربط مكتبة جافا سكريبت JQuery بصفحاتنا. وهكذا نجد السطر التالي:
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
ملاحظة: قم بتكييف إصدار jQuery مع إصدار Visual Studio الخاص بك.
تستخدم تقنية Ajax الخاصة بـ ASP.NET MVC JQuery. سنقوم بأنفسنا بكتابة بعض البرامج النصية JQuery. لذا، سنقدم الآن أساسيات JQuery التي يجب معرفتها لفهم البرامج النصية في هذا الفصل.
نقوم بإنشاء مشروع جديد [Exemple-04] داخل حلنا [Exemples]:
![]() |
لاستخدام Ajax مع ASP.NET MVC، يجب أن يتواجد سطر في ملف التكوين [Web.config] [1]:
<appSettings>
...
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
يسمح السطر 3 باستخدام Ajax في طرق العرض ASP.NET. وهو موجود بشكل افتراضي.
نقوم بإنشاء ملف HTML [JQuery-01.html] في المجلد [Content] للمشروع الجديد [2]:
![]() |
سيحتوي هذا الملف على المحتوى التالي:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/Scripts/jquery-1.8.2.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
- السطر 6: استيراد JQuery (قم بتكييف الإصدار مع إصدار Visual Studio الخاص بك)؛
- الأسطر 10-12: عنصر من الصفحة ذو المعرف [element1]. سنقوم بالتعامل مع هذا العنصر.
نقوم بعرض هذا الملف في متصفح Google Chrome [4] و [5]:
![]() |
باستخدام Google Chrome، اضغط على [Ctrl-Maj-I] لإظهار أدوات التطوير [6]. تتيح علامة التبويب [Console] [7] تنفيذ كود جافا سكريبت. نقدم في ما يلي أوامر جافا سكريبت التي يجب كتابتها مع شرح لها.
JS | النتيجة |
|
: يعرض مجموعة جميع العناصر ذات المعرف [element1]، وبالتالي عادةً ما تكون مجموعة مكونة من عنصر واحد أو صفر عنصر، لأنه لا يمكن وجود معرفين متطابقين في صفحة واحدة HTML. | ![]() |
|
: يطبق النص [blabla] على جميع عناصر المجموعة. ويؤدي ذلك إلى تغيير المحتوى المعروض على الصفحة | ![]() |
|
يخفي عناصر المجموعة. لم يعد النص [blabla] معروضًا. | ![]() |
|
: يعرض المجموعة مرة أخرى. وهذا يسمح لنا برؤية أن العنصر ذو المعرف [element1] يحتوي على السمة CSS style='display : none;' التي تجعل العنصر مخفيًا. | |
|
: يعرض عناصر المجموعة. يظهر النص [blabla] مرة أخرى. السمة CSS style='display : block;' هي التي تضمن هذا العرض. | ![]() |
|
: يحدد سمة لجميع عناصر المجموعة. السمة هنا هي [style] وقيمتها [color: red]. يتحول النص [blabla] إلى اللون الأحمر. | ![]() |
![]() | |
![]() |
تجدر الإشارة إلى أن URL للمتصفح لم يتغير خلال كل هذه العمليات. لم يكن هناك أي تبادل مع خادم الويب. كل شيء يحدث داخل المتصفح. الآن، لنلقِ نظرة على كود المصدر للصفحة:
![]() |
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/Scripts/jquery-1.8.2.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
هذا هو النص الأصلي. وهو لا يعكس بأي شكل من الأشكال المعالجات التي أجريناها على العنصر في الأسطر 10-12. من المهم تذكر ذلك عند إجراء تصحيح أخطاء جافا سكريبت. لذلك غالبًا ما يكون من غير المجدي عرض شفرة المصدر للصفحة المعروضة. لمعرفة شفرة المصدر للصفحة المعروضة حاليًا، سنقوم بما يلي:
![]() |
لدينا الآن ما يكفي من المعلومات لفهم البرامج النصية JS التالية.
7.3. تحديث صفحة باستخدام دفق HTML
7.3.1. طرق العرض
نقترح دراسة التطبيق التالي:
![]() |
- في [1]، وقت تحميل الصفحة؛
- في [2]، يتم إجراء العمليات الحسابية الأربع على عددين حقيقيين A و B؛
- في [3]، يتم تسجيل استجابة الخادم في منطقة من الصفحة؛
- في [4]، وقت الحساب. يختلف هذا الوقت عن وقت تحميل الصفحة [5]. وهذا الأخير يساوي [1] مما يدل على أن المنطقة [6] لم يتم إعادة تحميلها. علاوة على ذلك، لم يتغير URL [7] للصفحة.
7.3.2. وحدة التحكم، الإجراءات، النموذج، العرض
نقوم بإنشاء وحدة تحكم باسم [Premier]:
![]() |
لعرض العرض الأولي، نقوم بإنشاء الإجراء [Action01Get] التالي:
[HttpGet]
public ViewResult Action01Get()
{
ViewModel01 modèle = new ViewModel01();
modèle.HeureChargement = DateTime.Now.ToString("hh:mm:ss");
return View(modèle);
}
- السطر 4: إنشاء مثيل لنموذج العرض؛
- السطر 5: تهيئة وقت تحميل العرض؛
- السطر 6: عرض العرض [Action10Get.cshtml] ونموذجه.
نموذج [ViewModel01] هو التالي:
![]() |
using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Exemple_04.Models
{
[Bind(Exclude = "AplusB, AmoinsB, AmultipliéparB, AdiviséparB, Erreur, HeureChargement, HeureCalcul")]
public class ViewModel01
{
// نموذج
[Required(ErrorMessage="Donnée requise")]
[Display(Name="Valeur de A")]
[Range(0, Double.MaxValue, ErrorMessage = "Tapez un nombre positif ou nul")]
public double A { get; set; }
[Required(ErrorMessage = "Donnée requise")]
[Display(Name = "Valeur de B")]
[Range(0, Double.MaxValue, ErrorMessage="Tapez un nombre positif ou nul")]
public double B { get; set; }
// النتائج
public string AplusB { get; set; }
public string AmoinsB { get; set; }
public string AmultipliéparB { get; set; }
public string AdiviséparB { get; set; }
public string Erreur { get; set; }
public string HeureChargement { get; set; }
public string HeureCalcul { get; set; }
}
}
- الأسطر 11-14: القيمة A للنموذج؛
- الأسطر 15-18: القيمة B للنموذج؛
- الأسطر 21-24: نتائج العمليات الحسابية الأربع على A و B؛
- السطر 25: نص أي خطأ محتمل؛
- السطر 26: وقت تحميل العرض في المتصفح؛
- السطر 27: وقت حساب الحقول في الأسطر 21-24؛
- السطر 7: نموذج العرض هذا هو أيضًا نموذج إجراء. يتم استبعاد الحقول التي لا يتم إرسالها بواسطة المتصفح من هذا الأخير.
الطريقة [Action01Get.cshtml] هي كما يلي:
![]() |
@model Exemple_04.Models.ViewModel01
@{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "résultats",
HttpMethod = "post",
Url = Url.Action("Action01Post"),
LoadingElementId = "loading",
LoadingElementDuration = 1000
};
}
<!DOCTYPE html>
<html lang="fr-FR">
<head>
<meta name="viewport" content="width=device-width" />
<title>Ajax-01</title>
<link rel="stylesheet" href="~/Content/Site.css" />
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.en-US.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script type="text/javascript" src="~/Scripts/myScripts-01.js"></script>
</head>
<body>
<h2>Ajax - 01</h2>
<p><strong>Heure de chargement : @Model.HeureChargement</strong></p>
<h4>Opérations arithmétiques sur deux nombres réels A et B positifs ou nuls</h4>
@using (Ajax.BeginForm("Action01Post", null, ajaxOpts, new { id = "formulaire" }))
{
<table>
<thead>
<tr>
<th>@Html.LabelFor(m => m.A)</th>
<th>@Html.LabelFor(m => m.B)</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.TextBoxFor(m => m.A)</td>
<td>@Html.TextBoxFor(m => m.B)</td>
</tr>
<tr>
<td>@Html.ValidationMessageFor(m => m.A)</td>
<td>@Html.ValidationMessageFor(m => m.B)</td>
</tr>
</tbody>
</table>
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
}
<hr />
<div id="résultats" />
</body>
</html>
- السطر 1: نموذج العرض هو من النوع [ViewModel01]؛
- السطر 21: نحتاج إلى JQuery لكل من عمليات التحقق من الصحة و Ajax؛
- السطران 22-23: مكتبات التحقق من الصحة؛
- السطور 24-26: مكتبات التدويل؛
- السطر 27: مكتبة Ajax؛
- السطر 28: مكتبة جافا سكريبت محلية؛
- السطر 33: عرض وقت تحميل العرض؛
- السطر 35: نموذج Ajax - سنعود إليه لاحقًا؛
- السطور 40-41: تسميات إدخالات الأرقام A و B؛
- السطران 46-47: إدخال الأرقام A و B؛
- السطران 50-51: رسائل خطأ لإدخالات الأرقام A و B؛
- السطر 56: الزر الذي يرسل النموذج. سيتم إرسال هذا النموذج مع طلب Ajax؛
- السطر 57: صورة انتظار تُعرض أثناء طلب Ajax؛
- السطر 58: رابط لإرسال النموذج باستخدام طلب Ajax؛
- السطر 62: علامة <div> ذات المعرف [résultats]. هنا سنضع التدفق HTML الذي أرسله خادم الويب.
تعرض هذه الشاشة الصفحة التالية:
![]() |
لنلقِ نظرة الآن على الكود الذي يقوم بتحويل النموذج إلى Ajax:
...
@{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "résultats",
HttpMethod = "post",
Url = Url.Action("Action01Post"),
LoadingElementId = "loading",
LoadingElementDuration = 1000
};
}
...
@using (Ajax.BeginForm("Action01Post", null, ajaxOpts, new { id = "formulaire" }))
{
....
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
}
...
<div id="résultats" />
- السطر 15: بدلاً من استخدام [@Html.BeginForm]، نستخدم [@Ajax.BeginForm]. تسمح هذه الطريقة بالعديد من التحميلات الزائدة. الطريقة المستخدمة لها التوقيع التالي:
Ajax.BeginForm(string ActionName, RouteValueDictionary routeValues, AjaxOptions ajaxOptions, IDictionary<string,object> htmlAttributes)
نستخدم هنا المعلمات الفعلية التالية:
Action01Post: اسم الإجراء الذي سيعالج POST من النموذج،
null: لا توجد معلومات مسار لتقديمها،
ajaxOpts: خيارات استدعاء Ajax. تم تعريفها في الأسطر 6-10،
new { id = "formulaire" }: لتعيين السمة [id='formulaire'] إلى العلامة <form> التي تم إنشاؤها؛
خيارات Ajax المستخدمة هي التالية:
- السطر 8: هدف طلب Ajax URL؛
- السطر 7: طريقة طلب Ajax HTTP؛
- السطر 6: معرف منطقة الصفحة التي سيتم تحديثها بواسطة استجابة طلب Ajax؛
- السطر 9: معرف منطقة الصفحة التي سيتم عرضها أثناء طلب Ajax – عادةً ما تكون صورة انتظار. هنا سيتم عرض السطر 20. وهو يحتوي على صورة متحركة ترمز إلى الانتظار. في البداية، يتم إخفاء هذه الصورة بواسطة النمط [display : none]؛
- السطر 10: وقت الانتظار بالمللي ثانية قبل عرض الصورة المتحركة، وهو هنا 1 ثانية.
الرمز HTML الذي تم إنشاؤه بواسطة نموذج Ajax هو التالي:
<form action="/Premier/Action01Post" data-ajax="true" data-ajax-loading="#loading" data-ajax-loading-duration="1000" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#résultats" data-ajax-url="/Premier/Action01Post" id="formulaire" method="post"> <table>
...
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
</form>
<hr />
<div id="résultats" />
- السطر 1: العلامة <form> التي تم إنشاؤها. تجدر الإشارة إلى السمات [data-ajax-attr] التي تعكس قيم حقول الكائن من النوع [AjaxOptions] الذي تم ربطه بطلب Ajax. تتم إدارة هذه السمات بواسطة مكتبة Ajax. بدونها، تصبح العلامة <form> كما يلي:
<form action="/Premier/Action01Post" id="formulaire" method="post">
...
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
</form>
ونكون عندئذ أمام نموذج HTML كلاسيكي. وهذا هو الكود الذي سيتم تنفيذه إذا قام المستخدم بتعطيل جافا سكريبت على متصفحه. وعندئذ تصبح السطور 5-6 غير مستخدمة.
7.3.3. الإجراء [Action01Post]
الإجراء [Action01Post] الذي يعالج طلب Ajax HTTP هو التالي:
[HttpPost]
public PartialViewResult Action01Post(FormCollection postedData, SessionModel session)
{
// محاكاة الانتظار
Thread.Sleep(2000);
// تجسيد نموذج الإجراء
ViewModel01 modèle = new ViewModel01();
// وقت الحساب
modèle.HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// تحديث النموذج
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// إرجاع خطأ
modèle.Erreur = getErrorMessagesFor(ModelState);
return PartialView("Action01Error", modèle);
}
// في كل مرة من المرات، يتم محاكاة خطأ
int val = session.Randomizer.Next(2);
if (val == 0)
{
modèle.Erreur = "[erreur aléatoire]";
return PartialView("Action01Error", modèle);
}
// الحسابات
modèle.AplusB = string.Format("{0}", modèle.A + modèle.B);
modèle.AmoinsB = string.Format("{0}", modèle.A - modèle.B);
modèle.AmultipliéparB = string.Format("{0}", modèle.A * modèle.B);
modèle.AdiviséparB = string.Format("{0}", modèle.A / modèle.B);
// عرض
return PartialView("Action01Success", modèle);
}
- السطر 1: لا تعالج الإجراء سوى [POST]؛
- السطر 2: تقبل كنموذج للإجراء:
- [FormCollection postedData]: مجموعة القيم التي تم إرسالها بواسطة طلب Ajax POST،
- [SessionModel session]: عناصر الجلسة. نستخدم هنا تقنية موصوفة في الفقرة 4.10؛
- السطر 2: ستُرجع الإجراء جزءًا HTML وليس صفحة كاملة HTML؛
- السطر 5: بشكل مصطنع، نتوقف لمدة ثانيتين لمحاكاة إجراء Ajax طويل؛
- السطر 7: يتم إنشاء مثيل لنموذج من النوع [ViewModel01]؛
- السطر 9: يتم تهيئة وقت الحساب؛
- السطر 11: نحاول تحديث النموذج من النوع [ViewModel01] بالقيم المرسلة. نذكر أن هناك قيمتين: قيمتي العددين A و B؛
- السطر 12: يتم التحقق من نجاح هذا التحديث أم لا؛
- السطر 15: في حالة حدوث خطأ، يتم ملء الحقل [Erreur] في النموذج؛
- السطر 16: يتم عرض عرض جزئي [Action01Error.cshtml] باستخدام النموذج [ViewModel01]؛
- الأسطر 19-24: مرة كل مرتين، يتم محاكاة خطأ؛
- السطر 19: يتم إنشاء عدد صحيح عشوائي في النطاق [0,1]. يتم أخذ مولد الأرقام من الجلسة؛
- السطر 20: إذا كانت القيمة المولدة هي 0، يتم محاكاة خطأ؛
- السطر 22: يتم وضع رسالة الخطأ في النموذج؛
- السطر 23: يتم عرض عرض جزئي [Action01Error.cshtml] باستخدام النموذج [ViewModel01]؛
- الأسطر 26-29: يتم إجراء العمليات الحسابية على الأرقام A و B ويتم وضع النتائج في النموذج على شكل سلاسل أحرف؛
- السطر 31: يتم عرض عرض جزئي [Action01Success.cshtml] باستخدام النموذج [ViewModel01]؛
7.3.4. العرض [Action01Error]
الطريقة [Action01Error.cshtml] هي كما يلي:
@model Exemple_04.Models.ViewModel01
<h4>Résultats</h4>
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p style="color: red;">Une erreur s'est produite : @Model.Erreur</p>
يُذكر أن هذا التدفق الجزئي HTML سيتم إرساله استجابة لطلب Ajax HTTP من النوع POST وسيتم وضعه في الصفحة في منطقة id [résultats]. تأتي جميع هذه المعلومات من تكوين Ajax المستخدم في الصفحة الرئيسية [Action01Get.cshtml]:
@model Exemple_04.Models.ViewModel01
@{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "résultats",
HttpMethod = "post",
Url = Url.Action("Action01Post"),
LoadingElementId = "loading",
LoadingElementDuration = 1000
};
}
فيما يلي مثال على استجابة تحتوي على خطأ:
![]() |
7.3.5. طريقة العرض [Action01Success]
الطريقة [Action01Success.cshtml] هي كما يلي:
@model Exemple_04.Models.ViewModel01
<h4>Résultats</h4>
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p>A+B=@Model.AplusB</p>
<p>A-B=@Model.AmoinsB</p>
<p>A*B=@Model.AmultipliéparB</p>
<p>A/B=@Model.AdiviséparB</p>
مرة أخرى، سيتم إرسال هذا التدفق الجزئي HTML استجابةً لطلب Ajax HTTP من النوع POST ووضعه في الصفحة في منطقة id [résultats]:
![]() |
7.3.6. G إدارة الجلسة
لقد رأينا أن [Action01Post] يستخدم الجلسة. نموذج الجلسة هو النوع [SessionModel] التالي:
using System;
namespace Exemple_03.Models
{
public class SessionModel
{
public Random Randomizer { get; set; }
}
}
يتم تهيئة الجلسة في [Global.asax]:
// الجلسة
protected void Session_Start()
{
SessionModel sessionModel=new SessionModel();
sessionModel.Randomizer=new Random(DateTime.Now.Millisecond);
Session["data"] = sessionModel;
}
يتم ربط الجلسة بنموذج في [Application_Start]:
protected void Application_Start()
{
...
// رابطات النماذج
ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
}
تم وصف الفئة [SessionModelBinder].
7.3.7. إدارة صورة الانتظار
@model Exemple_04.Models.ViewModel01
@{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
...
LoadingElementId = "loading",
LoadingElementDuration = 1000
};
}
...
<body>
...
@using (Ajax.BeginForm("Action01Post", null, ajaxOpts, new { id = "formulaire" }))
{
...
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
}
...
عند بدء طلب Ajax، يتم عرض المنطقة ذات المعرف [loading] في السطر 7 بعد ثانية واحدة من [ligne 8]. هذه المنطقة هي الصورة الموجودة في السطر 21 والتي كانت مخفية في البداية. وهذا يعطي الواجهة التالية:
![]() |
7.3.8. إدارة الرابط [Calculer]
دعونا نلقي نظرة على الرابط [Calculer] في الصفحة الرئيسية [Action01Get.cshtml]:
<head>
<meta name="viewport" content="width=device-width" />
<title>Ajax-01</title>
...
<script type="text/javascript" src="~/Scripts/myScripts-01.js"></script>
</head>
<body>
<h2>Ajax - 01</h2>
<p><strong>Heure de chargement : @Model.HeureChargement</strong></p>
<h4>Opérations arithmétiques sur deux nombres réels A et B positifs ou nuls</h4>
@using (Ajax.BeginForm("Action01Post", null, ajaxOpts, new { id = "formulaire" }))
{
...
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
}
<hr />
<div id="résultats" />
- السطر 18: يؤدي النقر على الرابط [Calculer] إلى تنفيذ الدالة JS [postForm]. وهي محددة في الملف [myScripts-01.js] في السطر 5. هذا البرنامج النصي هو التالي:
![]() |
function postForm() {
// يتم إجراء استدعاء Ajax يدويًا باستخدام JQuery
var loading = $("#loading");
var formulaire = $("#formulaire");
var résultats = $('#النتائج');
$.ajax({
url: '/Premier/Action01Post',
type: 'POST',
data: formulaire.serialize(),
dataType: 'html',
begin: loading.show(),
success: function (data) {
loading.hide()
résultats.html(data);
}
})
}
// http://blog.instance-factory.com/?p=268
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$.validator.methods.date = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseDate(value));
}
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//استخدم المكون الإضافي Globalization لتحليل القيمة
var val = Globalize.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
تمت مناقشة وظائف الأسطر 19-37 بالفعل في الفقرة 6.1. وهي تدير تدويل الصفحات. لن نعود إليها. في الأسطر 1-17، نقوم يدويًا باستدعاء Ajax الذي كان يتم، في حالة الزر [Calculer]، بواسطة مكتبة Ajax المرتبطة بالمشروع. لهذا الغرض، نستخدم مكتبة JQuery المرتبطة بالمشروع.
- السطر 3: مرجع إلى المكون ذي المعرف [loading]. [$("#loading")] يعرض مجموعة العناصر ذات المعرف [loading]. لا يوجد سوى عنصر واحد؛
- السطر 4: إشارة إلى المكون ذي المعرف [formulaire]؛
- السطر 5: مرجع إلى المكون ذي المعرف [résultats]؛
- السطر 6: استدعاء Ajax مع خياراته؛
- السطر 7: هدف استدعاء Ajax URL؛
- السطر 8: الطريقة المستخدمة HTTP؛
- السطر 9: البيانات المرسلة. [formulaire.serialize] ينشئ السلسلة [A=val1&B=val2] من POST لنموذج معرف [formulaire]؛
- السطر 10: نوع البيانات المتوقع في الإرجاع. نعلم أن الخادم سيرسل دفق HTML؛
- السطر 11: الطريقة التي يجب تنفيذها عند بدء الطلب. هنا، نحدد أنه يجب عرض المكون ذي المعرف [loading]. هذه هي الصورة المتحركة للانتظار؛
- السطر 12: الطريقة التي يجب تنفيذها في حالة نجاح طلب Ajax. المعلمة [data] هي الاستجابة الكاملة من الخادم. نعلم أن هذا تدفق HTML؛
- السطر 13: يتم إخفاء إشارة الانتظار؛
- السطر 14: يتم تحديث المكون ذي المعرف [résultats] بـ HTML من المعلمة [data].
يُطلب من القارئ اختبار الرابط [Calculer]. يعمل هذا الرابط مثل الزر [Calculer] باستثناء خطأ واحد في ال . بمجرد استخدام هذا الرابط، يمكن عندئذٍ إرسال قيم A و B غير صالحة:
![]() |
- في [1] و [2]، تم إدخال قيم غير صالحة. يتم الإبلاغ عنها بواسطة أدوات التحقق من الصحة على جانب العميل؛
- في [3]، تم النقر على الرابط [Calculer]؛
- في [4]، كان هناك [POST] حيث تم الحصول على الرد [4].
عندما تكون القيم غير صالحة ويتم النقر على الزر [Calculer]، لا يتم إرسال [POST] إلى الخادم. في الحالة نفسها، مع الرابط [Calculer]، يتم إرسال [POST] إلى الخادم. لذلك، هناك سلوك للزر [Calculer] لم نتمكن من تكراره مع الرابط [Calculer]. بدلاً من محاولة حل هذه المشكلة الآن، سنتركها لمثال لاحق سيوضح أيضًا مشكلة أخرى تتعلق بالتحقق من صحة البيانات من جانب العميل.
7.4. تحديث صفحة HTML باستخدام تدفق JSON
في المثال السابق، كان خادم الويب يرد على طلب Ajax HTTP بتدفق HTML. في هذا التدفق، كانت هناك بيانات مصحوبة بتنسيق HTML. نقترح استئناف المثال السابق، ولكن هذه المرة باستخدام استجابات JSON (JavaScript Object Notation) التي تحتوي على البيانات فقط. الفائدة من ذلك هي أنه يتم نقل عدد أقل من البايتات.
7.4.1. الإجراء [Action02Get]
ستكون الإجراء [Action02Get] نقطة الدخول للتطبيق الجديد. ورمزها هو التالي:
@model Exemple_04.Models.ViewModel02
@{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
HttpMethod = "post",
Url = Url.Action("Action02Post"),
LoadingElementId = "loading",
LoadingElementDuration = 1000,
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"
};
}
<!DOCTYPE html>
<html lang="fr-FR">
<head>
<meta name="viewport" content="width=device-width" />
<title>Ajax-02</title>
....
<script type="text/javascript" src="~/Scripts/myScripts-02.js"></script>
</head>
<body>
<h2>Ajax - 02</h2>
<p><strong>Heure de chargement : @Model.HeureChargement</strong></p>
<h4>Opérations arithmétiques sur deux nombres réels A et B positifs ou nuls</h4>
@using (Ajax.BeginForm("Action02Post", null, ajaxOpts, new { id = "formulaire" }))
{
...
<p>
<input type="submit" value="Calculer" />
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<a href="javascript:postForm()">Calculer</a>
</p>
}
<hr />
<div id="entete">
<h4>Résultats</h4>
<p><strong>Heure de calcul : <span id="heureCalcul"/></strong></p>
</div>
<div id="résultats">
<p>A+B=<span id="AplusB"/></p>
<p>A-B=<span id="AmoinsB"/></p>
<p>A*B=<span id="AmultipliéparB"/></p>
<p>A/B=<span id="AdiviséparB"/></p>
</div>
<div id="erreur">
<p style="color: red;">Une erreur s'est produite : <span id="msg"/></p>
</div>
</body>
</html>
- الأسطر 4-14: خيارات استدعاء Ajax؛
- السطر 10: الدالة JS التي يجب تنفيذها عند بدء الطلب. يتم تعريف هذه الدالة في الملف JS المشار إليه في السطر 24؛
- السطر 11: الوظيفة JS التي يجب تنفيذها في حالة فشل الطلب؛
- السطر 12: الدالة JS التي يجب تنفيذها في حالة نجاح الطلب؛
- السطر 13: الدالة JS التي يجب تنفيذها بعد حصول طلب Ajax على نتيجته (فشل أو نجاح)؛
- الأسطر 40-43: منطقة ذات معرف [entete]؛
- الأسطر 44-49: منطقة معرف [résultats]. ستعرض نتائج العمليات الحسابية الأربع؛
- الأسطر 50-52: منطقة ذات معرف [erreur]. ستعرض أي رسالة خطأ محتملة.
7.4.2. الإجراء [Action02Post]
تتم معالجة طلب Ajax بواسطة الإجراء [Action02Post] التالي:
[HttpPost]
public JsonResult Action02Post(FormCollection postedData, SessionModel session)
{
// محاكاة الانتظار
Thread.Sleep(2000);
// التحقق من صحة النموذج
ViewModel02 modèle = new ViewModel02();
// ساعات التحميل والحساب
string HeureChargement = DateTime.Now.ToString("hh:mm:ss");
string HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// تحديث النموذج
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// تم إرجاع خطأ
return Json(new { Erreur = getErrorMessagesFor(ModelState), HeureCalcul = HeureCalcul });
}
// في كل مرة من المرات، يتم محاكاة خطأ
int val = session.Randomizer.Next(2);
if (val == 0)
{
// يتم إرجاع خطأ
return Json(new { Erreur = "[erreur aléatoire]", HeureCalcul = HeureCalcul });
}
// حسابات
string AplusB = string.Format("{0}", modèle.A + modèle.B);
string AmoinsB = string.Format("{0}", modèle.A - modèle.B);
string AmultipliéparB = string.Format("{0}", modèle.A * modèle.B);
string AdiviséparB = string.Format("{0}", modèle.A / modèle.B);
// يتم إرجاع النتائج
return Json(new { Erreur = "", AplusB = AplusB, AmoinsB = AmoinsB, AmultipliéparB = AmultipliéparB, AdiviséparB = AdiviséparB, HeureCalcul = HeureCalcul });
}
- السطر 2: تعرض الطريقة نوع [JsonResult]، أي نص بتنسيق JSON؛
- السطر 16: يتم عرض المعلومات في شكل مثيل لفئة مجهولة تم تسلسلها في JSON. وقد تم عرض الطريقة [getErrorMessagesFor] سابقًا. وستكون السلسلة JSON المرسلة إلى المتصفح على النحو التالي:
- السطر 31: نفس الإجراء بالنسبة للنتائج الحسابية. هذه المرة، ستكون السلسلة JSON المرسلة إلى المتصفح بالشكل التالي:
{"Erreur":"","AplusB":"4","AmoinsB":"-2","AmultipliéparB":"3","AdiviséparB":"0,333333333333333","HeureCalcul":"05:52:17"}
7.4.3. كود جافا سكريبت على جانب العميل
لنتذكر تكوين استدعاء Ajax في الصفحة HTML المرسلة إلى متصفح العميل:
AjaxOptions ajaxOpts = new AjaxOptions
{
HttpMethod = "post",
Url = Url.Action("Action02Post"),
LoadingElementId = "loading",
LoadingElementDuration = 1000,
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"
};
يتم تعريف الدوال JS المشار إليها في الأسطر 7-10 (على يمين علامة =) في الملف [myScripts-02.js] التالي:
// بيانات عامة
var entete;
var loading;
var résultats;
var erreur;
var heureCalcul;
var msg;
var AplusB;
var AmoinsB;
var AmultipliéparB;
var AdiviséparB;
var formulaire;
...
function postForm() {
...
}
// عند تحميل المستند
$(document).ready(function () {
formulaire = $("#formulaire");
entete = $("#entete");
loading = $("#loading");
erreur = $("#erreur");
résultats = $('#النتائج');
heureCalcul = $("#heureCalcul");
msg = $("#msg");
AplusB = $("#AplusB");
AmoinsB = $("#AmoinsB");
AmultipliéparB = $("#AmultipliéparB");
AdiviséparB = $("#AdiviséparB");
// يتم إخفاء بعض عناصر الصفحة
entete.hide();
résultats.hide();
erreur.hide();
});
// البدء
function OnBegin() {
....
}
// نهاية الطلب
function OnComplete() {
...
}
// نجاح
function OnSuccess(data) {
....
}
// خطأ
function OnFailure(request, error) {
...
}
- السطر 19: يتم تنفيذ الدالة JS عند انتهاء تحميل الصفحة في المتصفح؛
- الأسطر 20-30: يتم استرداد مراجع جميع مكونات الصفحة التي تهمنا. البحث عن مكون في صفحة ما له تكلفة، ومن الأفضل ألا يتم إجراؤه إلا مرة واحدة؛
- الأسطر 33-35: يتم إخفاء المكونات [entete] و [résultats] و [loading]؛
عند بدء تشغيل طلب Ajax، يتم تنفيذ الوظيفة التالية:
// بدء
function OnBegin() {
// إشارة الانتظار مضاءة
loading.show();
// يتم إخفاء بعض عناصر الصفحة
entete.hide();
résultats.hide();
erreur.hide();
}
- السطر 4: يتم عرض المكون [loading]. هذه هي الصورة المتحركة؛
- الأسطر 6-8: يتم إخفاء المكونات [entete] و [résultats] و [erreur]؛
إذا نجحت طلبات Ajax، يتم تنفيذ الكود JS التالي:
// نجاح
function OnSuccess(data) {
// عرض النتائج
heureCalcul.text(data.HeureCalcul);
entete.show();
if (data.Erreur != '') {
msg.text(data.Erreur);
erreur.show();
return;
}
// لا توجد أخطاء
AplusB.text(data.AplusB);
AmoinsB.text(data.AmoinsB);
AmultipliéparB.text(data.AmultipliéparB);
AdiviséparB.text(data.AdiviséparB);
résultats.show();
}
لفهم هذا الرمز، يجب تذكر النصين JSON اللذين من المحتمل إرسالهما كاستجابة للمتصفح:
في حالة حدوث خطأ، وإلا فإن السلسلة:
{"Erreur":"","AplusB":"4","AmoinsB":"-2","AmultipliéparB":"3","AdiviséparB":"0,333333333333333","HeureCalcul":"05:52:17"}
إذا أطلقنا على هذه السلسلة اسم [data]، فإن قيمة الحقل [Erreur] يتم الحصول عليها بواسطة الترميز [data.Erreur] أو [data["Erreur"]]، حسب الاختيار. وينطبق الأمر نفسه على الحقول الأخرى في السلسلة JSON. من ناحية أخرى، لتعيين نص غير منسق لمكون ذي معرف X، نكتب [X.text(chaine)]. لنعد إلى كود الدالة [OnSuccess]:
- السطر 2: [data] هي السلسلة JSON المستلمة؛
- السطر 4: المكون [heureCalcul] يتلقى قيمته؛
- السطر 5: يتم عرض المكون [entete]؛
- السطر 6: اختبار الحقل [Erreur] من السلسلة JSON؛
- السطر 7: يتم تعيين قيمة للمكون [msg]؛
- السطر 8: يتم عرض المكون [erreur]؛
- السطر 9: انتهى الأمر بالنسبة لحالة الخطأ؛
- السطر 12: المكون [AplusB] يتلقى قيمته؛
- السطر 13: المكون [AmoinsB] يتلقى قيمته؛
- السطر 14: المكون [AmultipliéparB] يتلقى قيمته؛
- السطر 15: المكون [AdiviséparB] يتلقى قيمته؛
- السطر 16: يتم عرض المكون [résultats].
سيتم تنفيذ الدالة [OnFailure] في حالة فشل طلب Ajax HTTP. يتم قياس هذا الفشل باستخدام الرمز HTTP الذي يرجعه الخادم. على سبيل المثال، يشير الرمز 500 [Internal Server Error] إلى أن الخادم لم يتمكن من تنفيذ الطلب. وظيفة [OnFailure] هي كما يلي:
// خطأ
function OnFailure(request, error) {
alert("L'erreur suivante s'est produite :" + error);
}
نكتفي بعرض مربع حوار مع الخطأ الذي حدث. في الواقع، يجب أن نكون أكثر دقة. سنقترح قريبًا حلًا آخر.
أخيرًا، يتم تنفيذ الدالة [OnComplete] عند انتهاء الطلب سواء بنجاح أو فشل.
// نهاية الطلب
function OnComplete() {
// إشارة الانتظار مطفأة
loading.hide();
}
نذكر هنا أن تكوين استدعاء Ajax في العرض [Action02Get.cshtml] هو ما يؤدي إلى استدعاء هذه الوظائف المختلفة:
AjaxOptions ajaxOpts = new AjaxOptions
{
...
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"
};
7.4.4. الرابط [Calculer]
الرمز HTML للرابط [Calculer] في العرض [Action02Get.cshtml] هو التالي:
<a href="javascript:postForm()">Calculer</a>
تم العثور على الوظيفة JS [postForm] في الملف المستورد [myScripts-02.js]:
<script type="text/javascript" src="~/Scripts/myScripts-02.js"></script>
ورمزها هو:
function postForm() {
// يتم إجراء استدعاء Ajax يدويًا باستخدام JQuery
$.ajax({
url: '/Premier/Action02Post',
type: 'POST',
data: formulaire.serialize(),
dataType: 'json',
beforeSend: OnBegin,
success: OnSuccess,
error: OnFailure,
complete: OnComplete
})
}
لقد صادفنا رمزًا مشابهًا من قبل.
- السطر 4: URL هدف استدعاء Ajax؛
- السطر 5: الأمر HTTP المستخدم في استدعاء Ajax؛
- السطر 6: القيم المرسلة. وهي نتيجة تسلسل قيم النموذج. ويشار إلى هذا النموذج، المحدد بواسطة المعرف [formulaire]، بواسطة المتغير [formulaire]. [data] ستكون سلسلة أحرف بالشكل [A=val1&B=val2]؛
- السطر 7: نوع تنسيق الرد المتوقع. وهي سلسلة JSON؛
- السطر 8: الدالة JS التي يجب تنفيذها عند بدء استدعاء Ajax؛
- السطر 9: الدالة JS التي يجب تنفيذها في حالة نجاح استدعاء Ajax؛
- السطر 10: وظيفة JS التي يجب تنفيذها في حالة فشل استدعاء Ajax؛
- السطر 11: وظيفة JS التي يجب تنفيذها بمجرد استلام الرد من الخادم، بغض النظر عن كونه ناجحًا أو فاشلًا.
لنعد إلى وظيفة Javascript التي تدير الحالة التي يفشل فيها استدعاء Ajax (السطر 10). يفشل استدعاء Ajax في حالات مختلفة، على سبيل المثال عندما يرسل الخادم رمز خطأ مثل [403 Forbidden]، [404 Not Found]، [500 Internal Server Error]، [301 Moved Permanently]، ...
في المثال السابق، تكون الدالة [OnFailure] كما يلي:
// خطأ
function OnFailure(request, error) {
alert("L'erreur suivante s'est produite :" + error);
}
بشكل عام، لا يقدم عرض الكائن [error] أي معلومات مفيدة. إذا تم استخدام استدعاء Ajax تم تنفيذه بواسطة JQuery، فيمكن استخدام الطريقة التالية [OnFailure]؛
// خطأ
function OnFailure(jqXHR) {
alert("Erreur : " + jqXHR.status + " " + jqXHR.statusText);
msg.html(jqXHR.responseText);
erreur.show();
}
يحتوي الكائن JQuery [jqXHR] على الخصائص التالية:
- responseText: نص استجابة الخادم؛
- status: رمز الخطأ الذي أعاده الخادم؛
- statusText: النص المرتبط برمز الخطأ هذا.
- السطر 3: يتم عرض رمز الخطأ والعبارة المرتبطة به؛
- السطر 4: يتم وضع استجابة الخادم HTML في المكون ذي المعرف [msg]؛
- السطر 5: يتم عرض منطقة معرف [erreur].
لاختبار وظيفة الخطأ هذه، سنقوم بإنشاء استثناء مصطنع في الإجراء [Action02Post]:
[HttpPost]
public JsonResult Action02Post(FormCollection postedData, SessionModel session)
{
// استثناء مصطنع لاختبار وظيفة الخطأ في استدعاء Ajax
throw new Exception();
// محاكاة الانتظار
Thread.Sleep(2000);
// التحقق من صحة النموذج
...
السطر 5 يطلق استثناءً. الآن لنختبر التطبيق:
![]() |
نحصل على الرد التالي [1] و [2]:
![]() |
تسمح لنا استجابة الخادم بمعرفة السطر الذي حدث فيه الخطأ في كود الخادم. غالبًا ما تكون هذه معلومة مفيدة. من الآن فصاعدًا، سنستخدم هذه التقنية لإدارة أخطاء استدعاءات Ajax.
7.5. تطبيق ويب ذو صفحة واحدة
تسمح تقنية Ajax بإنشاء تطبيقات ذات صفحة واحدة:
- الصفحة الأولى ناتجة عن طلب تقليدي من المتصفح؛
- يتم الحصول على الصفحات التالية من خلال استدعاءات Ajax. وبالتالي، لا يغير المتصفح في النهاية URL أبدًا ولا يقوم بتحميل صفحة جديدة أبدًا. يُطلق على هذا النوع من التطبيقات اسم "تطبيق ذو صفحة واحدة" (APU) أو باللغة الإنجليزية Single Page Application (SPA).
فيما يلي مثال بسيط على مثل هذا التطبيق. سيكون للتطبيق الجديد عرضان:
![]() |
![]() |
- في [1]، تتيح لنا الإجراء [Action03Get] الحصول على الصفحة الأولى، الصفحة 1؛
- في [2]، يتيح لنا رابط الانتقال إلى الصفحة 2 بفضل استدعاء Ajax؛
- في [3]، لم يتغير URL. الصفحة المعروضة هي الصفحة 2؛
- في [4]، يتيح لنا رابط العودة إلى الصفحة 1 بفضل استدعاء Ajax؛
- في [5]، لم يتغير URL. الصفحة المعروضة هي الصفحة 1.
رمز الإجراء [Action03Get] هو التالي:
[HttpGet]
public ViewResult Action03Get()
{
return View();
}
- السطر 4: يتم عرض العرض [Action03Get.cshtml].
الطريقة [Action03Get.cshtml] هي كما يلي:
![]() |
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action03Get</title>
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
</head>
<body>
<h3>Ajax - 03 - Single Page Application</h3>
<div id="content">
@Html.Partial("Page1")
</div>
</body>
</html>
- الأسطر 16-18: عنصر ذو معرف [content]. سيتم عرض الصفحات المختلفة في هذا العنصر؛
- السطر 17: بشكل افتراضي، ستظهر الصفحة [Page1.cshtml] أولاً.
الصفحة [Page1.cshtml] هي التالية:
<h4>Page 1</h4>
<p>
@Ajax.ActionLink("Page 2", "Action04", new { Page = 2 }, new AjaxOptions() { UpdateTargetId = "content" })
</p>
- السطر 1: عنوان الصفحة لتمييزها عن الصفحة 2؛
- السطر 3: رابط Ajax مع المعلمات التالية:
- نص الرابط [Page 2]؛
- الإجراء المستهدف للرابط [Action04]؛
- معلمات URL المطلوبة. وستكون هذه [/Premier/Action04?Page=2]؛
- خيارات استدعاء Ajax. هنا، فقط معرف المنطقة المراد تحديثها باستجابة الخادم. بالنسبة للخيارات الأخرى، يتم استخدام القيم الافتراضية عند وجودها. الطريقة الافتراضية لـ HTTP هي GET.
لنرى ما يحدث عند النقر على الرابط. يتم طلب URL [/Premier/Action04?Page=2] مع GET. ثم يتم تنفيذ الإجراء [Action04]:
[HttpGet]
public PartialViewResult Action04(string page = "1")
{
string vue = "Page1";
if (page == "2")
{
vue = "Page2";
}
return PartialView(vue);
}
- السطر 2: تُرجع الإجراء تدفقًا جزئيًا HTML؛
- السطر 2: الإجراء يستخدم السلسلة [page] كنموذج. ومع ذلك، من المعروف أن URL يحتوي على هذه المعلومات: [/Premier/Action04?Page=2]. تجدر الإشارة إلى أن النموذج لا يميز بين الأحرف الكبيرة والصغيرة؛
- الأسطر 4-8: ستتلقى [vue] القيمة [Page2]؛
- السطر 9: يتم عرض العرض الجزئي [Page2.cshtml].
الرؤية الجزئية [Page2.cshtml] هي كما يلي:
<h4>Page 2</h4>
<p>
@Ajax.ActionLink("Page 1", "Action04", new { Page = 1 }, new AjaxOptions() { UpdateTargetId = "content" })
</p>
وبالتالي، يقوم الخادم بإرجاع التدفق HTML أعلاه كرد على استدعاء Ajax GET [/Premier/Action04?Page=2]. نتذكر أن استدعاء Ajax هذا يستخدم هذا الرد لتحديث المنطقة ذات المعرف [content] (السطر 3 أدناه):
<h4>Page 1</h4>
<p>
@Ajax.ActionLink("Page 2", "Action04", new { Page = 2 }, new AjaxOptions() { UpdateTargetId = "content" })
</p>
يؤدي هذا إلى عرض جديد كما يلي [1]:
![]() |
وباتباع نفس المنطق، نرى أن النقر على الرابط [Page 1] من [1] سيؤدي إلى عرض [2].
لنعد إلى المخطط العام لتطبيق ASP.NET MVC:
![]() |
بفضل جافا سكريبت المدمج في الصفحات HTML والذي يتم تنفيذه في المتصفح، يمكن نقل الكود إلى المتصفح والحصول على البنية التالية:
![]() |
- في [1]، أصبحت طبقة الويب ASP.NET MVC واجهة ويب للوصول إلى البيانات، التي يتم تخزينها عادةً في قاعدة بيانات. لا تحتوي العروض المقدمة إلا على البيانات ولا تحتوي على أي تضمينات HTML، مثل تدفقات XML أو JSON؛
- في [2]: يعرض المتصفح طرق عرض ثابتة (أي غير مولدة ديناميكيًا) مقدمة من خادم ويب قد يكون أو لا يكون على نفس الجهاز الذي يوجد عليه خادم [1]. ثم يتم إثراء هذه العروض الثابتة بالبيانات التي يحصل عليها جافا سكريبت من واجهة الويب [1]؛
- يمكن تنظيم كود جافا سكريبت المدمج في الصفحات HTML في طبقات:
- تتولى الطبقة [présentation] التفاعلات مع المستخدم،
- الطبقة [DAO] تتولى الوصول إلى البيانات عبر خادم الويب [1] ،
- الطبقة [métier] تتوافق مع الطبقة [métier] التي كانت موجودة سابقًا على الخادم [1] والتي تم نقلها إلى المتصفح [2]؛
ميزة هذه البنية هي أنها تستلزم مهارات مختلفة:
- يتطلب كود خادم الويب [1] مهارات .NET ولكنه لا يتطلب مهارات Javascript، HTML، CSS؛
- يتطلب الكود المدمج في المتصفح [2] مهارات Javascript و HTML و CSS، ولكنه لا يتأثر بتقنية خادم الويب [1].
وبالتالي، تسهل هذه البنية العمل المتوازي لفرق ذات مهارات مختلفة. وهي تنطبق بشكل خاص على التطبيقات ذات الصفحة الواحدة.
7.6. تطبيق ويب ذو صفحة واحدة والتحقق من صحة البيانات من جانب العميل
لقد أشرنا سابقًا إلى وجود خلل في المثال Ajax-01. نذكر هنا السياق:
![]() |
- في [1] و [2]، تم إدخال قيم غير صالحة. تم الإبلاغ عنها بواسطة أدوات التحقق من صحة البيانات من جانب العميل؛
- في [3]، تم النقر على الرابط [Calculer]؛
- في [4]، حدث [POST] حيث تم الحصول على الرد [4].
عندما تكون القيم غير صالحة ويتم النقر على الزر [Calculer]، لا يتم إرسال [POST] إلى الخادم. في الحالة نفسها، مع الرابط [Calculer]، يتم إرسال [POST] إلى الخادم. لذلك، هناك سلوك للزر [Calculer] لم نتمكن من تكراره مع الرابط [Calculer].
سنستأنف هذا المثال في سياق جديد: سيكون للتطبيق عدة طرق عرض وسيكون من النوع [Application à Page Unique] الذي وصفناه للتو.
7.6.1. طرق عرض المثال
يحتوي المثال على عدة طرق عرض:
![]() |
- في [1]، العرض [Action05Get]؛
- في [2]، العرض الجزئي [Formulaire05]؛
- في [3]، العرض الجزئي [Failure05]؛
![]() |
- في [4]، العرض الجزئي [Success05].
التطبيق عبارة عن صفحة واحدة: يتم تحميلها بواسطة المتصفح عند الطلب الأول. ثم يتم تحديثها بواسطة استدعاءات Ajax.
يتم إنشاء الصفحات السابقة بواسطة العروض التالية [cshtml]:
![]() |
العرض الذي يتم تحميله في البداية هو العرض [Action05Get.cshtml] التالي:
@model Exemple_04.Models.ViewModel05
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="fr-FR">
<head>
<meta name="viewport" content="width=device-width" />
<title>Ajax-05</title>
<link rel="stylesheet" href="~/Content/Site.css" />
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.en-US.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script type="text/javascript" src="~/Scripts/myScripts-05.js"></script>
</head>
<body>
<h2>Ajax - 05, Page unique - Validation formulaire côté client</h2>
<p><strong>Heure de chargement : @Model.HeureChargement</strong></p>
<h4>Opérations arithmétiques sur deux nombres réels A et B positifs ou nuls</h4>
<img id="loading" style="display: none" src="~/Content/images/indicator.gif" />
<div id="content">
@Html.Partial("Formulaire05", Model)
</div>
</body>
</html>
يجب ملاحظة النقاط التالية:
- السطر 1: نموذج العرض هو النوع [ViewModel05] الذي سنقدمه قريبًا؛
- الأسطر 13-19: نجد هنا نصوص جافا سكريبت اللازمة لتنفيذ Ajax والتحقق من صحة البيانات من جانب العميل؛
- السطر 20: سنقوم بإضافة وظائف Javascript الخاصة بنا في [myScripts-05.js]؛
- السطر 27: الصورة المتحركة للانتظار؛
- الأسطر 28-30: علامة id [content]. سيتم إدراج العروض الجزئية [Formulaire05, Success05, Failure05] في هذه العلامة؛
- السطر 29: إدراج العرض الجزئي [Formulaire05].
العرض [Action05Get] مسؤول عن عرض الجزء [1] من الصفحة الأولية:
![]() |
ستقوم العرض الجزئي [Formulaire05] بإنشاء الجزء [2] أعلاه. رمزه هو التالي:
@model Exemple_04.Models.ViewModel05
@using (Html.BeginForm("Action05Post", "Premier", FormMethod.Post, new { id = "formulaire" }))
{
<table>
<thead>
<tr>
<th>@Html.LabelFor(m => m.A)</th>
<th>@Html.LabelFor(m => m.B)</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.TextBoxFor(m => m.A)</td>
<td>@Html.TextBoxFor(m => m.B)</td>
</tr>
<tr>
<td>@Html.ValidationMessageFor(m => m.A)</td>
<td>@Html.ValidationMessageFor(m => m.B)</td>
</tr>
</tbody>
</table>
<p>
<table>
<tbody>
<tr>
<td><a href="javascript:calculer()">Calculer</a>
</td>
<td style="width: 20px" />
<td><a href="javascript:effacer()">Effacer</a>
</td>
</tr>
</tbody>
</table>
</p>
}
- السطر 1: تقبل العرض الجزئي نموذجًا من النوع [ViewModel05]؛
- السطر 3: النموذج الذي تم إنشاؤه بواسطة الطريقة [Html.BeginForm]. نظرًا لأن هذا النموذج سيتم إرساله عبر استدعاء Ajax، فسيتم تجاهل المعلمات الثلاثة الأولى للطريقة. إلا إذا قام المستخدم بتعطيل Javascript في متصفحه. نحن نتجاهل هذه الاحتمالية هنا. المعلمة الرابعة مهمة. سيكون معرف النموذج هو [formulaire]؛
- الأسطر 5-22: نموذج إدخال الأرقام A و B؛
- السطر 27: رابط جافا سكريبت يطلق تنفيذ العمليات الحسابية الأربع على A و B؛
- السطر 30: رابط جافا سكريبت يمسح المدخلات وأي رسائل خطأ مرتبطة بها.
تجدر الإشارة إلى أن النموذج لا يحتوي على زر من النوع [submit]. سنضطر إلى إجراء عملية [Post] يدويًا للقيم A و B التي تم إدخالها.
إذا لم تكن هناك أخطاء، يتم عرض النتائج:
![]() |
يتم إنشاء الجزء [4] أعلاه بواسطة العرض الجزئي [Success05.cshtml] التالي:
@model Exemple_04.Models.ViewModel05
<hr />
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p>A=@Model.A</p>
<p>B=@Model.B</p>
<h4>Résultats</h4>
<p>A+B=@Model.AplusB</p>
<p>A-B=@Model.AmoinsB</p>
<p>A*B=@Model.AmultipliéparB</p>
<p>A/B=@Model.AdiviséparB</p>
<p>
<a href="javascript:retourSaisies()">Retour aux saisies</a>
</p>
- السطر 1: تتلقى العرض الجزئي [Success05.cshtml] نموذجًا من النوع [ViewModel05]؛
- السطر 12: رابط Javascript للعودة إلى الإدخالات.
في حالة حدوث خطأ، يتم عرض عرض جزئي آخر [3]:
![]() |
يتم إنشاء هذه العرض بواسطة الكود [Failure05.cshtml] التالي:
@model Exemple_04.Models.ViewModel05
<hr />
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p>A=@Model.A</p>
<p>B=@Model.B</p>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
@foreach (string msg in Model.Erreurs)
{
<li>@msg</li>
}
</ul>
<p>
<a href="javascript:retourSaisies()">Retour aux saisies</a>
</p>
- السطر 1: تستقبل العرض الجزئي [Failure05.cshtml] نموذجًا من النوع [ViewModel05]؛
- السطر 14: رابط جافا سكريبت للعودة إلى الإدخالات.
7.6.2. نموذج العروض
تشترك جميع العروض السابقة في نفس النموذج [ViewModel05]:
![]() |
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Exemple_04.Models
{
[Bind(Exclude = "AplusB, AmoinsB, AmultipliéparB, AdiviséparB, Erreurs, HeureChargement, HeureCalcul")]
public class ViewModel05
{
// نموذج
[Required(ErrorMessage="Donnée A requise")]
[Display(Name="Valeur de A")]
[Range(0, Double.MaxValue, ErrorMessage = "Tapez un nombre A positif ou nul")]
public string A { get; set; }
[Required(ErrorMessage = "Donnée B requise")]
[Display(Name = "Valeur de B")]
[Range(0, Double.MaxValue, ErrorMessage="Tapez un nombre B positif ou nul")]
public string B { get; set; }
// النتائج
public string AplusB { get; set; }
public string AmoinsB { get; set; }
public string AmultipliéparB { get; set; }
public string AdiviséparB { get; set; }
public List<string> Erreurs { get; set; }
public string HeureChargement { get; set; }
public string HeureCalcul { get; set; }
}
}
هذا هو النموذج [ViewModel01] الذي تم عرضه سابقًا مع بعض الاختلافات الطفيفة:
- السطران 15 و19: أصبحت الحقول A وB من النوع [string] لعرض حقول إدخال فارغة بدلاً من حقول بقيمة 0، عند العرض الأولي لنموذج الإدخال؛
- السطران 14 و18: هذا لا يمنع التحقق من القيمة المدخلة باستخدام أداة التحقق من الصحة [Range]؛
- السطر 26: قائمة برسائل الخطأ المعروضة بواسطة طريقة العرض [Failure05].
7.6.3. بيانات النطاق [Session]
في الفقرة 7.3.6، رأينا أن بيانات الجلسة كانت مغلفة في النموذج [SessionModel] التالي:
![]() |
using System;
namespace Exemple_03.Models
{
public class SessionModel
{
// مولد الأرقام العشوائية
public Random Randomizer { get; set; }
}
}
تم توسيع نموذج الجلسة هذا ليشمل قيمتي A و B:
using System;
namespace Exemple_03.Models
{
public class SessionModel
{
// مولد الأرقام العشوائية
public Random Randomizer { get; set; }
// قيمتي A و B
public string A { get; set; }
public string B { get; set; }
}
}
من الضروري بالفعل حفظ قيمتي A و B في الجلسة كما يوضح التسلسل التالي:
الطلب 1
![]() |
الطلب 2
![]() |
في [4]، نجد الإدخالات التي تمت في [1]. ولكن هناك طلبان منفصلان HTTP. من المعروف أن الذاكرة بين الطلبين HTTP هي الجلسة. لكي يتمكن الطلب الثاني من العثور على القيم التي أرسلها الطلب الأول، يجب أن يتم وضع هذه القيم في الجلسة.
7.6.4. إجراء الخادم [Action05Get]
الإجراء [Action05Get] هو الإجراء الذي يعرض الصفحة الفردية الأولية. ورمزه هو التالي:
[HttpGet]
public ViewResult Action05Get()
{
ViewModel05 modèle = new ViewModel05();
modèle.HeureChargement = DateTime.Now.ToString("hh:mm:ss");
return View(modèle);
}
- السطر 6: يتم عرض العرض [Action05Get.cshtml] الذي تمت دراسته سابقًا باستخدام نموذج من النوع [ViewModel05]؛
7.6.5. إجراء العميل [Calculer]
دعونا ندرس تفاعلات المستخدم مع طرق العرض:
![]() |
الرابط [1] هو رابط جافا سكريبت:
<a href="javascript:calculer()">Calculer</a>
توجد وظيفة جافا سكريبت [calculer] في الملف [myScripts-05.js]:
<script type="text/javascript" src="~/Scripts/myScripts-05.js"></script>
رمز وظيفة جافا سكريبت [calculer] هو التالي:
// البيانات العامة
var content;
var loading;
function calculer() {
// أولاً المراجع على DOM
var formulaire = $("#formulaire");
// ثم التحقق من صحة النموذج
if (!formulaire.validate().form()) {
// نموذج غير صالح - انتهى
return;
}
// يتم إجراء استدعاء Ajax يدويًا
$.ajax({
url: '/Premier/Action05FaireCalcul',
type: 'POST',
data: formulaire.serialize(),
dataType: 'html',
beforeSend: function () {
loading.show();
},
success: function (data) {
content.html(data);
},
complete: function () {
loading.hide();
},
error: function (jqXHR) {
// عرض استجابة الخادم
content.html(jqXHR.responseText);
}
})
}
function retourSaisies() {
...
}
function effacer() {
...
}
// عند تحميل المستند
$(document).ready(function () {
// استرداد مراجع المكونات المختلفة للصفحة
loading = $("#loading");
content = $("#content");
// نقوم بتخزين الصورة المتحركة مؤقتًا
loading.hide();
});
- يُذكر أن كود جافا سكريبت يتم تنفيذه دائمًا على جانب العميل، في المتصفح؛
- السطر 44: يتم تنفيذ وظيفة JS عند انتهاء التحميل الأولي للصفحة الفردية؛
- السطر 46: إشارة إلى الصورة المتحركة ذات المعرف [loading]؛
- السطر 47: إشارة إلى المنطقة ذات المعرف [content]. هذه المنطقة هي التي تستقبل العروض الجزئية [Formulaire05, Success05, Failure05]؛
- السطران 2-3: تم إعلان متغيرات السطرين 46-47 كمتغيرات عامة حتى تتمكن الوظائف الأخرى من الوصول إليها. هناك تكلفة للبحث عن العناصر في الصفحة (السطران 46-47). لا داعي لتكرار هذا البحث إذا كان بالإمكان تجنبه؛
- السطر 5: الدالة [calculer]؛
- السطر 7: يتم استرداد مرجع على النموذج. أعطته طريقة العرض الجزئية [Formulaire05] المعرف [formulaire]؛
- السطر 9: تنفذ هذه التعليمات أدوات التحقق من صحة النموذج من جانب العميل. وهذا ما كان مفقودًا في الخطأ الملحوظ في الصفحة 183. يتم توفير هذه الطريقة بواسطة المكتبة [jquery.unobstrusive-ajax] المستخدمة من قبل الصفحة الفردية:
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
تُرجع التعليمات [false] إذا تم الإعلان عن عدم صحة النموذج؛
- السطر 11: لا يتم إجراء استدعاء Ajax إلى الخادم إذا كان النموذج غير صالح؛
- الأسطر 14-32: يتم إجراء استدعاء Ajax إلى الخادم؛
- السطر 15: الهدف URL هو إجراء الخادم [Action05FaireCalcul]؛
- السطر 16: يتم طلبها عبر [POST]؛
- السطر 17: القيم المرسلة. وهي المدخلات في النموذج، وهنا قيم A و B؛
- الأسطر 22-24: في حالة نجاح استدعاء Ajax، تقوم الدالة [calculer] بتحديث منطقة id [content] باستخدام التدفق HTML المرسل من الخادم.
هذا التدفق HTML هو الذي أرسلته الإجراء [Action05FaireCalcul] الذي استهدفته استدعاء Ajax. رمز هذا الإجراء من جانب الخادم هو التالي:
[HttpPost]
public PartialViewResult Action05FaireCalcul(FormCollection postedData, SessionModel session)
{
// القالب
ViewModel05 modèle = new ViewModel05();
// وقت الحساب
modèle.HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// تحديث النموذج
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// إرجاع خطأ
modèle.Erreurs = getListOfMessagesFor(ModelState);
return PartialView("Failure05", modèle);
}
...
}
- السطر 1: لا تقبل الإجراء سوى [post]؛
- السطر 2: تعرض عرضًا جزئيًا؛
- السطر 2: تتلقى كمعلمات القيم المرسلة (postedData) ونموذج الجلسة (session)؛
- السطر 5: يتم إنشاء نموذج العرض الجزئي؛
- السطر 7: يتم تحديثه بوقت الحساب؛
- السطر 9: نحاول تطبيق القيم المرسلة على النموذج. سيتم عندئذٍ تنفيذ أدوات التحقق الخاصة به. قد نتساءل عن سبب بذل هذا الجهد في حين أن أدوات التحقق من جانب العميل تمنع POST إذا كانت البيانات المدخلة غير صالحة. في الواقع، نحن غير متأكدين من مصدر POST. ربما تم إنشاؤه بواسطة كود لا يخصنا. لذلك يجب دائمًا إجراء عمليات التحقق من جانب الخادم؛
- السطر 10: نختبر ما إذا كانت أدوات التحقق قد نجحت؛
- السطر 13: إذا كان النموذج غير صالح، يتم تحديثه بقائمة بالأخطاء. لن ندخل في تفاصيل الطريقة الداخلية [getListOfMessagesFor]، وهي مشابهة للطريقة [GetErrorMessagesFor] الموضحة في الصفحة 65؛
- السطر 14: يتم عرض العرض الجزئي [Failure05] مع نموذجه. نذكر رمز هذا العرض؛
@model Exemple_04.Models.ViewModel05
<hr />
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p>A=@Model.A</p>
<p>B=@Model.B</p>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
@foreach (string msg in Model.Erreurs)
{
<li>@msg</li>
}
</ul>
<p>
<a href="javascript:retourSaisies()">Retour aux saisies</a>
</p>
- الأسطر 7-12: يتم عرض قائمة أخطاء النموذج باستخدام علامة <ul>.
نتذكر أن الدالة JS [calculer] فيأصل [Post] في إجراء الخادم [Action05FaireCalcul] ستضع هذا التدفق HTML في منطقة id [content]. وهذا يعطي شيئًا مثل هذا:
![]() |
لنواصل دراسة كود الإجراء [Action05FaireCalcul]:
[HttpPost]
public PartialViewResult Action05FaireCalcul(FormCollection postedData, SessionModel session)
{
// القالب
ViewModel05 modèle = new ViewModel05();
...
// يتم وضع قيم A و B في الجلسة
session.A = modèle.A;
session.B = modèle.B;
// لا توجد أخطاء حتى الآن
List<string> erreurs = new List<string>();
// في كل مرة من المرات، يتم محاكاة خطأ
int val = session.Randomizer.Next(2);
if (val == 0)
{
erreurs.Add("[erreur aléatoire]");
}
if (erreurs.Count != 0)
{
modèle.Erreurs = erreurs;
return PartialView("Failure05", modèle);
}
// الحسابات
double A = double.Parse(modèle.A);
double B = double.Parse(modèle.B);
modèle.AplusB = string.Format("{0}", A + B);
modèle.AmoinsB = string.Format("{0}", A - B);
modèle.AmultipliéparB = string.Format("{0}", A * B);
modèle.AdiviséparB = string.Format("{0}", A / B);
// عرض
return PartialView("Success05", modèle);
}
- السطر 7: تم إعلان النموذج صالحًا؛
- السطران 8-9: يتم إدخال القيمتين A و B في الجلسة. نريد أن نتمكن من العثور عليهما في الاستعلام الذي سيلي؛
- السطور 11-22: يتم إنشاء خطأ عشوائي مرة كل مرتين؛
- السطور 24-29: يتم إجراء العمليات الحسابية الأربع على الأعداد الحقيقية التي تم إدخالها؛
- السطر 31: يتم إرجاع العرض الجزئي [Success05] مع نموذجه. هذا العرض الجزئي هو التالي:
@model Exemple_04.Models.ViewModel05
<hr />
<p><strong>Heure de calcul : @Model.HeureCalcul</strong></p>
<p>A=@Model.A</p>
<p>B=@Model.B</p>
<h4>Résultats</h4>
<p>A+B=@Model.AplusB</p>
<p>A-B=@Model.AmoinsB</p>
<p>A*B=@Model.AmultipliéparB</p>
<p>A/B=@Model.AdiviséparB</p>
<p>
<a href="javascript:retourSaisies()">Retour aux saisies</a>
</p>
نتذكر أن الدالة JS [calculer] فيأصل [Post] في إجراء الخادم [Action05FaireCalcul] ستضع هذا التدفق HTML في منطقة id [content]. وهذا يعطي شيئًا مثل هذا:
![]() |
7.6.6. إجراء العميل [Effacer]
يتيح رابط جافا سكريبت [Effacer] إعادة النموذج إلى حالته الأولية:
![]() | ![]() |
في النموذج، يتم تعريف الرابط JS [Effacer] على النحو التالي:
<a href="javascript:effacer()">Effacer</a>
يتم تعريف الوظيفة JS [effacer] في الملف [myScripts-05.js] على النحو التالي:
// البيانات الإجمالية
var content;
var loading;
function calculer() {
...
}
function retourSaisies() {
...
}
function effacer() {
// أولاً المراجع في DOM
var formulaire = $("#formulaire");
var A = $("#A");
var B = $("#B");
// نقوم بتعيين قيم صالحة للمدخلات
A.val("0");
B.val("0");
// ثم يتم التحقق من صحة النموذج لإزالة
// أي رسائل خطأ محتملة
formulaire.validate().form();
// ثم نخصص سلاسل فارغة لحقول الإدخال
A.val("");
B.val("");
}
// عند تحميل المستند
$(document).ready(function () {
// نسترد مراجع المكونات المختلفة للصفحة
loading = $("#loading");
content = $("#content");
// نخفي الصورة المتحركة
loading.hide();
});
- الأسطر 15-17: يتم استرداد المراجع الخاصة بمختلف عناصر DOM (نموذج كائن المستند)؛
- السطور 19-20: يتم إدخال قيم صالحة في حقول إدخال الأرقام A و B؛
- السطر 23: يتم تنفيذ أدوات التحقق من الصحة من جانب العميل. ونظرًا لأن قيمتي A و B صالحتان، فسيؤدي ذلك إلى إخفاء أي رسائل خطأ قد يتم عرضها؛
- السطران 25-26: يتم إدخال سلاسل فارغة في حقول إدخال الأرقام A و B؛
7.6.7. إجراء العميل [Retour aux Saisies]
يتيح رابط جافا سكريبت [Retour aux Saisies] العودة إلى النموذج بعد الحصول على النتائج:
![]() | ![]() |
في النموذج، يتم تعريف الرابط JS [Retour aux Saisies] على النحو التالي:
<a href="javascript:retourSaisies()">Retour aux saisies</a>
يتم تعريف الوظيفة JS [retourSaisies] في الملف [myScripts-05.js] على النحو التالي:
// البيانات العامة
var content;
var loading;
function calculer() {
...
}
function retourSaisies() {
// يتم إجراء استدعاء Ajax يدويًا
$.ajax({
url: '/Premier/Action05RetourSaisies',
type: 'POST',
dataType: 'html',
beforeSend: function () {
loading.show();
},
success: function (data) {
content.html(data);
},
complete: function () {
loading.hide();
// IMPORTANT !! التحقق من الصحة
$.validator.unobtrusive.parse($("#formulaire"));
},
error: function (jqXHR) {
content.html(jqXHR.responseText);
}
})
}
function effacer() {
...
}
// عند تحميل المستند
$(document).ready(function () {
// نسترد مراجع المكونات المختلفة للصفحة
loading = $("#loading");
content = $("#content");
// نقوم بتخزين الصورة المتحركة مؤقتًا
loading.hide();
});
- الأسطر 11-29: استدعاء Ajax؛
- السطر 12: الهدف URL؛
- السطر 13: سيتم طلبها بواسطة أمر HTTP POST. إنه POST بدون معلمات مرسلة. ولهذا السبب، لا نجد سطرًا من النوع:
في استدعاء Ajax؛
- السطر 14: التدفق المتوقع من الخادم هو تدفق HTML؛
- الأسطر 18-20: سيُستخدم هذا التدفق HTML لتحديث المنطقة ذات المعرف [content]؛
إجراء الخادم [Action05RetourSaisies] هو كما يلي:
[HttpPost]
public PartialViewResult Action05RetourSaisies(SessionModel session)
{
// عرض
return PartialView("Formulaire05", new ViewModel05() { A = session.A, B = session.B });
}
- السطر 2: تتلقى الإجراء كمعلمة نموذج الجلسة الذي قمنا فيه مسبقًا بتخزين قيم A و B التي تم إدخالها؛
- السطر 5: يتم إرجاع العرض الجزئي [Formulaire05] بنموذج من النوع [ViewModel05] حيث يتم تهيئة الحقول A و B بقيم A و B المأخوذة من الجلسة؛
الآن لنعد إلى كود وظيفة جافا سكريبت [retourSaisies]:
function retourSaisies() {
// يتم إجراء استدعاء Ajax يدويًا
$.ajax({
url: '/Premier/Action05RetourSaisies',
type: 'POST',
dataType: 'html',
beforeSend: function () {
loading.show();
},
success: function (data) {
content.html(data);
},
complete: function () {
loading.hide();
// IMPORTANT !! التحقق
$.validator.unobtrusive.parse($("#formulaire"));
},
error: function (jqXHR) {
content.html(jqXHR.responseText);
}
})
}
- السطر 13: الطريقة التي يتم تنفيذها عند انتهاء استدعاء Ajax؛
- السطر 14: يتم إخفاء الصورة المتحركة للانتظار؛
- السطر 16: تعليمات غير مفهومة بالنسبة لي تم العثور عليها على الإنترنت لحل المشكلة التالية: في النموذج المعروض بواسطة الرابط [Retour aux saisies]، لم تعد أدوات التحقق من صحة البيانات من جانب العميل تعمل. أثناء البحث عن معلومات حول مكتبة JS [jquery.unobtrusive-ajax]، وجدت الحل في السطر 16. تقوم هذه التعليمات بتحليل النموذج، ربما لتفعيل أدوات التحقق من صحة البيانات على جانب العميل.
7.7. جعل تطبيق ASP.NET متاحًا على الإنترنت
انظر الفقرة 9.26.
7.8. إنشاء تطبيق أصلي لنظام Android من تطبيق ذي صفحة واحدة APU
انظر الفقرة 9.27.

















































