7. تحويل تطبيق ASP.NET MVC إلى Ajax
7.1. دور AJAX في تطبيق الويب
في الوقت الحالي، تتميز الأمثلة التعليمية التي درسناها بالبنية التالية:
![]() |
للتبديل من عرض [View1] إلى عرض [View2]، يقوم المتصفح بما يلي:
- يرسل طلبًا إلى تطبيق الويب؛
- يستقبل العرض [View2] ويعرضه بدلاً من العرض [View1].
هذا هو النمط الكلاسيكي:
- طلب من المتصفح؛
- يقوم خادم الويب بإنشاء عرض استجابة للعميل؛
- عرض هذا العرض الجديد بواسطة المتصفح.
هناك نمط آخر للتفاعل بين المتصفح وخادم الويب: AJAX (جافا سكريبت غير متزامن و XML). يتضمن هذا تفاعلات بين العرض الذي يعرضه المتصفح وخادم الويب. يواصل المتصفح القيام بما يجيده — عرض HTML — ولكنه الآن يخضع لسيطرة جافا سكريبت المضمنة في عرض HTML المعروض. تتم العملية على النحو التالي:
![]() |
- في [1]، يحدث حدث على الصفحة المعروضة في المتصفح (النقر على زر، تغيير في النص، إلخ). يتم اعتراض هذا الحدث بواسطة JavaScript (JS) المضمن في الصفحة؛
- في [2]، يقوم كود JavaScript بإرسال طلب HTTP تمامًا كما كان سيفعل المتصفح. الطلب غير متزامن: يمكن للمستخدم الاستمرار في التفاعل مع الصفحة دون أن يتم حظره أثناء انتظار استجابة HTTP. يتبع الطلب تدفق المعالجة القياسي. لا شيء (أو القليل جدًا) يميزه عن الطلب القياسي؛
- في [3]، يتم إرسال استجابة إلى عميل JavaScript. وبدلاً من عرض HTML كامل، عادةً ما يتم إرسال عرض HTML جزئي أو موجز XML أو JSON (ترميز كائنات JavaScript)؛
- في [4]، يسترد JavaScript هذا الرد ويستخدمه لتحديث منطقة من صفحة HTML المعروضة.
بالنسبة للمستخدم، يحدث تغيير في العرض لأن ما يراه قد تغير. ومع ذلك، لا يتم إعادة تحميل الصفحة بالكامل؛ بل يحدث تعديل جزئي فقط للصفحة المعروضة. وهذا يساعد في جعل الصفحة أكثر سلاسة وتفاعلية: نظرًا لعدم إعادة تحميل الصفحة بالكامل، يمكننا التعامل مع أحداث لم يكن من الممكن إدارتها في السابق. على سبيل المثال، تقديم قائمة من الخيارات للمستخدم أثناء كتابة الأحرف في حقل الإدخال. مع كل حرف جديد يتم كتابته، يتم إرسال طلب AJAX إلى الخادم، والذي يعرض بعد ذلك اقتراحات إضافية. بدون AJAX، كان هذا النوع من المساعدة في الإدخال مستحيلًا في السابق. لم نكن نستطيع إعادة تحميل صفحة جديدة مع كل حرف يتم كتابته.
7.2. أساسيات jQuery و JavaScript
غالبًا ما قمنا بتضمين مكتبة jQuery JavaScript في صفحاتنا. على سبيل المثال، ستجد السطر التالي:
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
ملاحظة: قم بمطابقة إصدار jQuery مع إصدار Visual Studio الخاص بك.
تستخدم تقنية Ajax في ASP.NET MVC jQuery. سنقوم بكتابة بعض نصوص jQuery بأنفسنا. لذا دعونا الآن نستعرض أساسيات jQuery التي تحتاج إلى معرفتها لفهم النصوص في هذا الفصل.
نقوم بإنشاء مشروع جديد [Example-04] ضمن حل [Examples] الخاص بنا:
![]() |
لاستخدام 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-Shift-I] لفتح أدوات المطور [6]. تتيح لك علامة التبويب [Console] [7] تشغيل كود JavaScript. أدناه، نقدم أوامر JavaScript التي يجب كتابتها ونشرح وظائفها.
JS | result |
|
: يُرجع مجموعة جميع العناصر التي تحمل المعرف [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. من المهم تذكر ذلك عند تصحيح أخطاء JavaScript. في مثل هذه الحالات، غالبًا ما يكون من غير الضروري عرض شفرة المصدر للصفحة المعروضة. لعرض شفرة المصدر للصفحة المعروضة حاليًا، اتبع الخطوات التالية:

لدينا الآن ما يكفي من المعرفة لفهم نصوص 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
{
// form
[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; }
// results
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 مع المعرف [results]. هذا هو المكان الذي سنضع فيه ناتج 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 = "form" }: لتعيين السمة [id='form'] إلى العلامة <form> التي تم إنشاؤها؛
خيارات Ajax المستخدمة هي كما يلي:
- السطر 8: عنوان URL الهدف لطلب HTTP Ajax؛
- السطر 7: طريقة طلب HTTP لـ Ajax؛
- السطر 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 قياسي. سيتم تنفيذ هذا الرمز إذا قام المستخدم بتعطيل JavaScript في متصفحه. عندئذٍ لن يتم استخدام السطرين 5 و6.
7.3.3. الإجراء [Action01Post]
إجراء [Action01Post] الذي يتعامل مع طلب Ajax HTTP هو كما يلي:
[HttpPost]
public PartialViewResult Action01Post(FormCollection postedData, SessionModel session)
{
// wait simulation
Thread.Sleep(2000);
// action model instantiation
ViewModel01 modèle = new ViewModel01();
// calculation time
modèle.HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// model update
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// returns an error
modèle.Erreur = getErrorMessagesFor(ModelState);
return PartialView("Action01Error", modèle);
}
// every other time, an error is simulated
int val = session.Randomizer.Next(2);
if (val == 0)
{
modèle.Erreur = "[erreur aléatoire]";
return PartialView("Action01Error", modèle);
}
// calculations
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);
// view
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: في حالة حدوث خطأ، يتم ملء حقل [Error] في النموذج؛
- السطر 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 سيتم إرساله استجابةً لطلب HTTP من نوع POST عبر Ajax، وسيتم وضعه في الصفحة ضمن المنطقة التي تحمل المعرف [results]. وتأتي كل هذه المعلومات من إعدادات 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 استجابة لطلب HTTP من نوع POST عبر Ajax ووضعه على الصفحة في المنطقة التي تحمل المعرف [results]:

7.3.6. إدارة جلسات G
لقد رأينا أن [Action01Post] يستخدم الجلسة. نموذج الجلسة هو النوع [SessionModel] التالي:
using System;
namespace Exemple_03.Models
{
public class SessionModel
{
public Random Randomizer { get; set; }
}
}
يتم تهيئة الجلسة في [Global.asax]:
// Session
protected void Session_Start()
{
SessionModel sessionModel=new SessionModel();
sessionModel.Randomizer=new Random(DateTime.Now.Millisecond);
Session["data"] = sessionModel;
}
يتم ربط الجلسة بنموذج في [Application_Start]:
protected void Application_Start()
{
...
// model binders
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 بعد ثانية واحدة [السطر 8]. هذه المنطقة هي الصورة من السطر 21، والتي كانت مخفية في البداية. وينتج عن ذلك الواجهة التالية:
![]() |
7.3.8. التعامل مع رابط [Calculate]
دعونا نفحص رابط [Calculate] في الصفحة الرئيسية [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: يؤدي النقر على رابط [Calculate] إلى تشغيل دالة JS [postForm]. تم تعريف هذه الدالة في ملف [myScripts-01.js] في السطر 5. النص البرمجي كالتالي:
![]() |
function postForm() {
// on fait un appel Ajax à la main avec JQuery
var loading = $("#loading");
var formulaire = $("#formulaire");
var résultats = $('#results');
$.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) {
//Use the Globalization plugin to parse the value
var val = Globalize.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
تمت تغطية الوظائف الواردة في الأسطر 19–37 سابقًا في القسم 6.1. وهي تتولى عملية تدويل الصفحات. ولن نعيد تناولها هنا. أما في الأسطر 1–17، فنقوم يدويًّا بإجراء استدعاء Ajax، وهو ما كانت مكتبة Ajax الخاصة بالمشروع تتولى تنفيذه سابقًا في حالة زر [Calculate]. ولهذا الغرض، نستخدم مكتبة jQuery الخاصة بالمشروع.
- السطر 3: إشارة إلى المكون الذي يحمل المعرف [loading]. [$("#loading")] تُرجع مجموعة العناصر التي تحمل المعرف [loading]. لا يوجد سوى عنصر واحد؛
- السطر 4: إشارة إلى المكون الذي يحمل المعرف [form]؛
- السطر 5: إشارة إلى المكون الذي يحمل المعرف [results]؛
- السطر 6: استدعاء Ajax مع خياراته؛
- السطر 7: عنوان URL الهدف لاستدعاء Ajax؛
- السطر 8: طريقة HTTP المستخدمة؛
- السطر 9: البيانات المرسلة. [form.serialize] ينشئ سلسلة POST [A=val1&B=val2] للنموذج الذي يحمل المعرف [form]؛
- السطر 10: نوع البيانات المتوقع في الاستجابة. نعلم أن الخادم سيعيد دفق HTML؛
- السطر 11: الطريقة التي يجب تنفيذها عند بدء الطلب. هنا، نحدد أنه يجب عرض المكون الذي يحمل المعرف [loading]. هذه هي صورة التحميل المتحركة؛
- السطر 12: الطريقة التي يجب تنفيذها في حالة نجاح طلب Ajax. المعلمة [data] هي الاستجابة الكاملة من الخادم. نعلم أن هذا تيار HTML؛
- السطر 13: نخفي مؤشر التحميل؛
- السطر 14: نقوم بتحديث المكون الذي يحمل المعرف [results] باستخدام HTML من المعلمة [data].
ندعو القارئ إلى اختبار الرابط [Calculate]. يعمل هذا الرابط تمامًا مثل الزر [Calculate]، باستثناء رسالة الخطأ " ." بمجرد استخدام هذا الرابط، يمكن إدخال قيم غير صالحة لـ A و B:
![]() |
- في [1] و [2]، أدخلنا قيمًا غير صالحة. تم تمييزها بواسطة أدوات التحقق من الصحة من جانب العميل؛
- في [3]، نقرنا على رابط [حساب]؛
- في [4]، حدث [POST] لأننا تلقينا الاستجابة [4].
عندما تكون القيم غير صالحة ونضغط على زر [حساب]، لا يحدث طلب [POST] إلى الخادم. في نفس السيناريو، يؤدي استخدام رابط [حساب] إلى تشغيل طلب [POST] إلى الخادم. لذلك، هناك سلوك لزر [حساب] لم نتمكن من إعادة إنتاجه باستخدام رابط [حساب]. بدلاً من محاولة حل هذه المشكلة الآن، سنتركها لمثال لاحق سيوضح أيضًا مشكلة أخرى تتعلق بالتحقق من صحة البيانات من جانب العميل.
7.4. تحديث صفحة HTML باستخدام موجز JSON
في المثال السابق، استجاب خادم الويب لطلب Ajax HTTP بتدفق HTML. احتوى هذا التدفق على بيانات مصحوبة بتنسيق HTML. سنعيد النظر في المثال السابق، هذه المرة باستخدام استجابات JSON (ترميز كائنات JavaScript) التي تحتوي على البيانات فقط. وتتمثل الميزة في نقل عدد أقل من البايتات.
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: منطقة ذات المعرف [header]؛
- الأسطر 44-49: منطقة ذات المعرف [results]. ستعرض نتائج العمليات الحسابية الأربع؛
- الأسطر 50-52: منطقة معرف [error]. ستعرض أي رسائل خطأ.
7.4.2. الإجراء [Action02Post]
يتم معالجة طلب Ajax بواسطة الإجراء [Action02Post] التالي:
[HttpPost]
public JsonResult Action02Post(FormCollection postedData, SessionModel session)
{
// wait simulation
Thread.Sleep(2000);
// model validation
ViewModel02 modèle = new ViewModel02();
// loading and calculation times
string HeureChargement = DateTime.Now.ToString("hh:mm:ss");
string HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// model update
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// returns an error
return Json(new { Erreur = getErrorMessagesFor(ModelState), HeureCalcul = HeureCalcul });
}
// every other time, an error is simulated
int val = session.Randomizer.Next(2);
if (val == 0)
{
// returns an error
return Json(new { Erreur = "[erreur aléatoire]", HeureCalcul = HeureCalcul });
}
// calculations
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);
// we return the results
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] التالي:
// global data
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 loading
$(document).ready(function () {
formulaire = $("#formulaire");
entete = $("#entete");
loading = $("#loading");
erreur = $("#erreur");
résultats = $('#résultats');
heureCalcul = $("#heureCalcul");
msg = $("#msg");
AplusB = $("#AplusB");
AmoinsB = $("#AmoinsB");
AmultipliéparB = $("#AmultipliéparB");
AdiviséparB = $("#AdiviséparB");
// hide certain page elements
entete.hide();
résultats.hide();
erreur.hide();
});
// start
function OnBegin() {
....
}
// end of query
function OnComplete() {
...
}
// success
function OnSuccess(data) {
....
}
// error
function OnFailure(request, error) {
...
}
- السطر 19: الدالة JS التي يتم تنفيذها عند انتهاء تحميل الصفحة في المتصفح؛
- الأسطر 20–30: نسترد مراجع جميع مكونات الصفحة التي نهتم بها. البحث عن مكون في الصفحة يتطلب تكلفة، لذا من الأفضل القيام بذلك مرة واحدة فقط؛
- الأسطر 33–35: يتم إخفاء مكونات [header] و[results] و[loading]؛
عندما يبدأ طلب Ajax، يتم تنفيذ الدالة التالية:
// start
function OnBegin() {
// wait signal on
loading.show();
// hide certain page elements
entete.hide();
résultats.hide();
erreur.hide();
}
- السطر 4: يتم عرض مكون [loading]. هذه هي الصورة المتحركة؛
- الأسطر 6–8: يتم إخفاء مكونات [header] و[results] و[error]؛
إذا نجح طلب Ajax، يتم تنفيذ كود JS التالي:
// réussite
function OnSuccess(data) {
// affichage résultats
heureCalcul.text(data.HeureCalcul);
entete.show();
if (data.Erreur != '') {
msg.text(data.Erreur);
erreur.show();
return;
}
// pas d'erreur
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]، يتم الحصول على قيمة حقل [Error] باستخدام الترميز [data.Error] أو [data["Error"]], حسب الرغبة. وينطبق الأمر نفسه على الحقول الأخرى في سلسلة JSON. بالإضافة إلى ذلك، لتعيين نص غير منسق لمكون بمعرف X، نكتب [X.text(string)]. لنعد إلى كود الدالة [OnSuccess]:
- السطر 2: [data] هي سلسلة JSON المستلمة؛
- السطر 4: يتلقى المكون [calculationTime] قيمته؛
- السطر 5: يتم عرض المكون [entete]؛
- السطر 6: يتحقق من حقل [Error] في سلسلة JSON؛
- السطر 7: يتلقى المكون [msg] قيمته؛
- السطر 8: يتم عرض المكون [error]؛
- السطر 9: هذا كل شيء بالنسبة لحالة الخطأ؛
- السطر 12: يتلقى المكون [AplusB] قيمته؛
- السطر 13: يتلقى المكون [AminusB] قيمته؛
- السطر 14: يتلقى المكون [AmultipliedbyB] قيمته؛
- السطر 15: يتم تعيين قيمة للمكون [AdividedbyB]؛
- السطر 16: يتم عرض المكون [results].
سيتم تنفيذ الدالة [ OnFailure] في حالة فشل طلب Ajax HTTP. يتم تحديد هذا الفشل من خلال رمز حالة HTTP الذي يرجعه الخادم. على سبيل المثال، يشير الرمز 500 [Internal Server Error] إلى أن الخادم لم يتمكن من معالجة الطلب. الدالة [OnFailure] هي كما يلي:
// error
function OnFailure(request, error) {
alert("L'erreur suivante s'est produite :" + error);
}
نقوم ببساطة بعرض مربع حوار يحتوي على الخطأ الذي حدث. في الواقع، يجب أن نكون أكثر تحديدًا. سنقترح قريبًا حلاً آخر.
أخيرًا، يتم تنفيذ الدالة [OnComplete] عند اكتمال الطلب، سواء نجح أم فشل.
// end of query
function OnComplete() {
// wait signal off
loading.hide();
}
لاحظ أن تكوين استدعاء Ajax في عرض [Action02Get.cshtml] هو الذي يتسبب في استدعاء هذه الوظائف المختلفة:
AjaxOptions ajaxOpts = new AjaxOptions
{
...
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"
};
7.4.4. رابط [Calculate]
فيما يلي كود HTML للرابط [Calculate] في طريقة العرض [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() {
// make a manual Ajax call with 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: القيم المنشورة. هذه هي نتيجة تسلسل قيم النموذج. يُشار إلى النموذج، المحدد بواسطة المعرف [form]، بواسطة المتغير [form]. سيكون [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] كما يلي:
// error
function OnFailure(request, error) {
alert("L'erreur suivante s'est produite :" + error);
}
بشكل عام، لا يوفر عرض كائن [error] أي معلومات مفيدة. إذا كنت تستخدم استدعاء Ajax تم إجراؤه باستخدام jQuery، فيمكنك استخدام طريقة [OnFailure] التالية؛
// error
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: نعرض المنطقة التي تحمل المعرف [error].
لاختبار معالجة الأخطاء هذه، سنقوم بإنشاء استثناء مصطنع في الإجراء [Action02Post]:
[HttpPost]
public JsonResult Action02Post(FormCollection postedData, SessionModel session)
{
// an artificial exception to test the Ajax call error function
throw new Exception();
// wait simulation
Thread.Sleep(2000);
// model validation
...
السطر 5 يرمي استثناءً. الآن دعونا نختبر التطبيق:
![]() |
نحصل على الاستجابة التالية [1] و[2]:
![]() |
يتيح لنا رد الخادم معرفة السطر الذي حدث فيه الخطأ في كود الخادم. وغالبًا ما تكون هذه معلومة مفيدة. من الآن فصاعدًا، سنستخدم هذه التقنية لمعالجة الأخطاء في استدعاءات Ajax.
7.5. تطبيق ويب أحادي الصفحة
تتيح لنا تقنية Ajax إنشاء تطبيقات ذات صفحة واحدة:
- يتم تحميل الصفحة الأولى عبر طلب متصفح قياسي؛
- يتم الحصول على الصفحات اللاحقة عبر مكالمات Ajax. ونتيجة لذلك، لا يغير المتصفح عنوان URL أبدًا ولا يقوم بتحميل صفحة جديدة أبدًا. يُطلق على هذا النوع من التطبيقات اسم تطبيق صفحة واحدة (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 بالمعلمات التالية:
- تسمية الرابط [الصفحة 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: ستتلقى [view] القيمة [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]:
![]() |
وباتباع نفس المنطق، نرى أن النقر على رابط [الصفحة 1] في [1] سيعرض [2].
لنعد إلى الرسم التخطيطي العام لتطبيق ASP.NET MVC:
![]() |
بفضل JavaScript المضمن في صفحات HTML والذي يتم تنفيذه في المتصفح، يمكننا نقل الكود إلى المتصفح وتحقيق البنية التالية:
![]() |
- في [1]، أصبحت طبقة الويب ASP.NET MVC واجهة ويب للوصول إلى البيانات، التي يتم تخزينها عادةً في قاعدة بيانات. تحتوي العروض التي يتم إرجاعها على البيانات فقط ولا تحتوي على علامات HTML، مثل موجزات XML أو JSON؛
- في [2]: يعرض المتصفح طرق عرض ثابتة (أي غير مولدة ديناميكيًا) يتم توفيرها بواسطة خادم ويب قد يكون أو لا يكون على نفس الجهاز الذي يوجد عليه الخادم [1]. ثم يتم إثراء طرق العرض الثابتة هذه بالبيانات التي يتم الحصول عليها بواسطة JavaScript من واجهة الويب [1]؛
- يمكن تنظيم كود JavaScript المضمن في صفحات HTML في طبقات:
- تتولى طبقة [العرض] التعامل مع تفاعلات المستخدم،
- تتعامل طبقة [DAO] مع الوصول إلى البيانات عبر خادم الويب [1]،
- طبقة [منطق الأعمال] تتوافق مع طبقة [منطق الأعمال] التي كانت موجودة سابقًا على الخادم [1] وتم نقلها إلى المتصفح [2]؛
وتتمثل ميزة هذه البنية في أنها تعتمد على مجموعات مهارات مختلفة:
- يتطلب كود خادم الويب [1] مهارات في .NET ولكنه لا يتطلب مهارات في JavaScript أو HTML أو CSS؛
- يتطلب الكود المضمن في المتصفح [2] مهارات في JavaScript و HTML و CSS، ولكنه لا يعتمد على تقنية خادم الويب [1].
وبالتالي، تسهل هذه البنية العمل المتوازي بين الفرق ذات المهارات المختلفة. وهي مناسبة بشكل خاص لتطبيقات الصفحة الواحدة.
7.6. تطبيق الويب أحادي الصفحة والتحقق من صحة البيانات من جانب العميل
ذكرنا سابقًا وجود شذوذ في مثال Ajax-01. فيما يلي ملخص للسياق:
![]() |
- في [1] و[2]، تم إدخال قيم غير صالحة. تم الإبلاغ عن هذه القيم بواسطة أدوات التحقق من صحة البيانات من جانب العميل؛
- في [3]، نقرنا على رابط [حساب]؛
- في [4]، حدث [POST] لأننا تلقينا الاستجابة [4].
عندما تكون القيم غير صالحة ويتم النقر على زر [حساب]، لا يحدث طلب [POST] إلى الخادم. في نفس السيناريو، يؤدي النقر على رابط [حساب] إلى تشغيل طلب [POST] إلى الخادم. لذلك، هناك سلوك لزر [حساب] لم نتمكن من إعادة إنتاجه باستخدام رابط [حساب].
سنعيد النظر في هذا المثال في سياق جديد: سيحتوي التطبيق على عدة طرق عرض وسيكون من نوع [تطبيق صفحة واحدة] الذي وصفناه للتو.
7.6.1. طرق العرض في المثال
يحتوي المثال على عدة طرق عرض:
![]() |
- في [1]، طريقة العرض [Action05Get]؛
- في [2]، العرض الجزئي [Form05]؛
- في [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: تحتوي على نصوص JavaScript اللازمة لـ Ajax والتحقق من صحة البيانات من جانب العميل؛
- السطر 20: سنضيف وظائف JavaScript الخاصة بنا في [myScripts-05.js]؛
- السطر 27: صورة التحميل المتحركة؛
- الأسطر 28–30: علامة `id` [content]. هذا هو المكان الذي سيتم فيه إدراج العروض الجزئية [Form05، Success05، Failure05]؛
- السطر 29: إدراج العرض الجزئي [Form05].
العرض [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 في متصفحه. نحن نتجاهل هذه الاحتمالية هنا. المعلمة الرابعة مهمة. سيحمل النموذج المعرف [form]؛
- الأسطر 5-22: النموذج لإدخال الرقمين A و B؛
- السطر 27: رابط JavaScript الذي يؤدي إلى تنفيذ العمليات الحسابية الأربع على A و B؛
- السطر 30: رابط JavaScript يمسح الإدخالات وأي رسائل خطأ مرتبطة بها.
لاحظ أن النموذج لا يحتوي على زر [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: رابط JavaScript للعودة إلى حقول الإدخال.
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
{
// form
[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; }
// results
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
{
// the random number generator
public Random Randomizer { get; set; }
}
}
تم توسيع نموذج الجلسة هذا ليشمل قيمتي A و B:
using System;
namespace Exemple_03.Models
{
public class SessionModel
{
// the random number generator
public Random Randomizer { get; set; }
// the values of A and 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. إجراء العميل [Calculate]
دعونا نفحص تفاعلات المستخدم مع طرق العرض:
![]() |
الرابط [1] هو رابط JavaScript:
<a href="javascript:calculer()">Calculer</a>
توجد دالة JavaScript [calculate] في الملف [myScripts-05.js]:
<script type="text/javascript" src="~/Scripts/myScripts-05.js"></script>
فيما يلي كود وظيفة JavaScript [calculate]:
// global data
var content;
var loading;
function calculer() {
// first the references on DOM
var formulaire = $("#formulaire");
// then validate the form
if (!formulaire.validate().form()) {
// invalid form - terminated
return;
}
// make a manual Ajax call
$.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) {
// display server response
content.html(jqXHR.responseText);
}
})
}
function retourSaisies() {
...
}
function effacer() {
...
}
// document loading
$(document).ready(function () {
// retrieve the references of the page's various components
loading = $("#loading");
content = $("#content");
// we hide the moving image
loading.hide();
});
- لاحظ أن كود JavaScript يتم تنفيذه دائمًا على جانب العميل، في المتصفح؛
- السطر 44: وظيفة JS التي يتم تنفيذها عند اكتمال التحميل الأولي للصفحة الواحدة؛
- السطر 46: إشارة إلى الصورة المتحركة ذات المعرف [loading]؛
- السطر 47: إشارة إلى المنطقة التي تحمل المعرف [content]. تتلقى هذه المنطقة العروض الجزئية [Form05، Success05، Failure05]؛
- السطران 2-3: يتم إعلان المتغيرات من السطرين 46-47 على أنها عالمية حتى تتمكن الدوال الأخرى من الوصول إليها. هناك تكلفة مرتبطة بالبحث عن العناصر في الصفحة (السطران 46-47). لا داعي لتكرار هذا البحث إذا كان من الممكن تجنبه؛
- السطر 5: الدالة [calculate]؛
- السطر 7: يتم استرداد مرجع للنموذج. وقد منحته طريقة العرض الجزئية [Form05] المعرف [form]؛
- السطر 9: تعمل هذه التعليمات على تشغيل أدوات التحقق من صحة النموذج من جانب العميل. وهذا هو ما كان مفقودًا في المشكلة التي تم تحديدها في الصفحة 176. يتم توفير هذه الطريقة بواسطة مكتبة [jquery.unobtrusive-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، تقوم الدالة [calculate] بتحديث المنطقة ذات المعرف [content] باستخدام دفق HTML المرسل من الخادم.
هذا الدفق HTML هو الذي أرسلته الإجراء [Action05FaireCalcul] الذي يستهدفه استدعاء Ajax. رمز هذا الإجراء من جانب الخادم هو كما يلي:
[HttpPost]
public PartialViewResult Action05FaireCalcul(FormCollection postedData, SessionModel session)
{
// model
ViewModel05 modèle = new ViewModel05();
// calculation time
modèle.HeureCalcul = DateTime.Now.ToString("hh:mm:ss");
// model update
TryUpdateModel(modèle, postedData);
if (!ModelState.IsValid)
{
// returns an error
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] الموصوفة في الصفحة 60؛
- السطر 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 [calculate]، التي تطلق [Post] إلى إجراء الخادم [Action05FaireCalcul]، ستضع هذا الإخراج HTML في المنطقة ذات المعرف [content]. وينتج عن ذلك شيء مثل هذا:
![]() |
لنواصل فحص كود الإجراء [Action05FaireCalcul]:
[HttpPost]
public PartialViewResult Action05FaireCalcul(FormCollection postedData, SessionModel session)
{
// model
ViewModel05 modèle = new ViewModel05();
...
// we put the values of A and B in session
session.A = modèle.A;
session.B = modèle.B;
// no errors so far
List<string> erreurs = new List<string>();
// every other time, an error is simulated
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);
}
// calculations
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);
// view
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 [calculate]، التي تطلق [Post] إلى إجراء الخادم [Action05FaireCalcul]، ستضع دفق HTML هذا في المنطقة ذات المعرف [content]. وينتج عن ذلك شيء مثل هذا:
![]() |
7.6.6. زر [Clear]
يعيد رابط JavaScript [Clear] تعيين النموذج إلى حالته الأولية:


في النموذج، يتم تعريف رابط JS [مسح] على النحو التالي:
<a href="javascript:effacer()">Effacer</a>
يتم تعريف دالة JS [clear] في ملف [myScripts-05.js] على النحو التالي:
// global data
var content;
var loading;
function calculer() {
...
}
function retourSaisies() {
...
}
function effacer() {
// first the references on DOM
var formulaire = $("#formulaire");
var A = $("#A");
var B = $("#B");
// valid values are assigned to entries
A.val("0");
B.val("0");
// then validate the form to make
// any error msg
formulaire.validate().form();
// then assign empty strings to the input fields
A.val("");
B.val("");
}
// document loading
$(document).ready(function () {
// retrieve the references of the page's various components
loading = $("#loading");
content = $("#content");
// we hide the moving image
loading.hide();
});
- السطور 15-17: نسترد الإشارات إلى عناصر مختلفة من DOM (نموذج كائن المستند)؛
- السطور 19-20: نضع قيمًا صالحة في حقول الإدخال للأرقام A و B؛
- السطر 23: تشغيل أدوات التحقق من الصحة من جانب العميل. نظرًا لأن قيمتي A و B صالحتان، سيؤدي ذلك إلى إزالة أي رسائل خطأ قد تظهر؛
- السطور 25–26: يتم إدخال سلاسل فارغة في حقول الإدخال الخاصة بالرقمين A و B؛
7.6.7. الإجراء من جانب العميل [العودة إلى حقول الإدخال]
يتيح لك رابط JavaScript [العودة إلى حقول الإدخال] العودة إلى النموذج بعد الحصول على النتائج:


في النموذج، يتم تعريف رابط JS [العودة إلى الإدخال] على النحو التالي:
<a href="javascript:retourSaisies()">Retour aux saisies</a>
تم تعريف دالة JS [retourSaisies] في الملف [myScripts-05.js] على النحو التالي:
// global data
var content;
var loading;
function calculer() {
...
}
function retourSaisies() {
// make a manual Ajax call
$.ajax({
url: '/Premier/Action05RetourSaisies',
type: 'POST',
dataType: 'html',
beforeSend: function () {
loading.show();
},
success: function (data) {
content.html(data);
},
complete: function () {
loading.hide();
// IMPORTANT!!! validation
$.validator.unobtrusive.parse($("#formulaire"));
},
error: function (jqXHR) {
content.html(jqXHR.responseText);
}
})
}
function effacer() {
...
}
// document loading
$(document).ready(function () {
// retrieve the references of the page's various components
loading = $("#loading");
content = $("#content");
// we hide the moving image
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)
{
// view
return PartialView("Formulaire05", new ViewModel05() { A = session.A, B = session.B });
}
- السطر 2: يتلقى الإجراء كمعلمة نموذج الجلسة الذي قمنا مسبقًا بتخزين قيم A و B المدخلة فيه؛
- السطر 5: نُرجع العرض الجزئي [Form05] بنموذج من النوع [ViewModel05] حيث نحرص على تهيئة الحقول A و B بقيم A و B المأخوذة من الجلسة؛
الآن دعونا نعود إلى كود دالة JavaScript [returnInput]:
function retourSaisies() {
// make a manual Ajax call
$.ajax({
url: '/Premier/Action05RetourSaisies',
type: 'POST',
dataType: 'html',
beforeSend: function () {
loading.show();
},
success: function (data) {
content.html(data);
},
complete: function () {
loading.hide();
// IMPORTANT!!! validation
$.validator.unobtrusive.parse($("#formulaire"));
},
error: function (jqXHR) {
content.html(jqXHR.responseText);
}
})
}
- السطر 13: الطريقة التي يتم تنفيذها عند اكتمال استدعاء Ajax؛
- السطر 14: يتم إخفاء صورة التحميل المتحركة؛
- السطر 16: تعليمات غامضة إلى حد ما وجدتها على الإنترنت لحل المشكلة التالية: في النموذج المعروض بواسطة الرابط [العودة إلى الإدخال]، لم تعد أدوات التحقق من صحة البيانات من جانب العميل تعمل. أثناء البحث عن معلومات حول مكتبة JS [jquery.unobtrusive-ajax]، وجدت الحل في السطر 16. يقوم بتحليل النموذج، ربما لتنشيط أدوات التحقق من صحة البيانات من جانب العميل.
7.7. جعل تطبيق ASP.NET متاحًا على الإنترنت
انظر القسم 9.26.
7.8. إنشاء تطبيق Android أصلي من تطبيق APU أحادي الصفحة
انظر القسم 9.27.








































