(function($, kendo) { $.extend(true, kendo.ui.validator, { rules: { remote: function(input) { var remoteAttr = input.attr("data-val-remote-url"); if (typeof remoteAttr === typeof undefined || remoteAttr === false) { return true; } var isInvalid = true; var data = {}; data[input.attr('name')] = input.val(); $.ajax({ url: remoteAttr, mode: "abort", port: "validate" + input.attr('name'), dataType: "json", type: input.attr("data-val-remote-type"), data: data, async: false, success: function(response) { isInvalid = response; } }); return !isInvalid; } }, messages: { remote: function(input) { return input.data('val-remote'); } } }); })(jQuery, kendo);
مدل برنامه
using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Mvc4TwitterBootStrapTest.Models { public class User { [DisplayName("نام")] [Required(ErrorMessage="لطفا نام را تکمیل کنید")] public string Name { set; get; } [DisplayName("نام خانوادگی")] [Required(ErrorMessage = "لطفا نام خانوادگی را تکمیل کنید")] public string LastName { set; get; } } }
کنترلر برنامه
using System.Web.Mvc; using Mvc4TwitterBootStrapTest.Models; namespace Mvc4TwitterBootStrapTest.Controllers { public class HomeController : Controller { [HttpGet] public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(User user) { if (this.ModelState.IsValid) { if (user.Name != "Vahid") { this.ModelState.AddModelError("", "لطفا مشکلات را برطرف کنید!"); this.ModelState.AddModelError("Name", "نام فقط باید وحید باشد!"); return View(user); } // todo: save ... return RedirectToAction("Index"); } return View(user); } } }
طراحی View سازگار با Twitter bootstrap
@model Mvc4TwitterBootStrapTest.Models.User @{ ViewBag.Title = "تعریف کاربر"; } @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { @class = "form-horizontal" })) { @Html.ValidationSummary(true, null, new { @class = "alert alert-error alert-block" }) <fieldset> <legend>تعریف کاربر</legend> <div class="control-group"> @Html.LabelFor(x => x.Name, new { @class = "control-label" }) <div class="controls"> @Html.TextBoxFor(x => x.Name) @Html.ValidationMessageFor(x => x.Name, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(x => x.LastName, new { @class = "control-label" }) <div class="controls"> @Html.TextBoxFor(x => x.LastName) @Html.ValidationMessageFor(x => x.LastName, null, new { @class = "help-inline" }) </div> </div> <div class="form-actions"> <button type="submit" class="btn btn-primary"> ارسال</button> </div> </fieldset> }
1) کلاس form-horizontal به فرم جاری اضافه شده است تا در ادامه بتوانیم برچسبها را در کنار تکست باکسها به صورت افقی نمایش دهیم.
2) به ValidationSummary کلاسهای alert alert-error alert-block انتساب داده شدهاند تا نمایش خطای کلی یک فرم، متناسب با Twitter bootstrap شود.
3) هر خاصیت، با یک div دارای کلاس control-group محصور شده است.
4) هر برچسب دارای کلاس control-label است.
5) به هر ValidationMessageFor کلاس help-inline انتساب داده شده است.
6) کنترلهای ورودی برنامه در divایی با کلاس controls محصور شدهاند.
7) قسمت دکمه فرم، در div ایی با کلاس form-actions قرار گرفته تا یک زمینه خاکستری در اینجا ظاهر شود.
8) دکمه فرم، با کلاس btn خاص bootstrap تزئین شده.
در این حالت به شکل فوق خواهیم رسید. همانطور که ملاحظه میکنید در صورتیکه بر روی دکمه ارسال کلیک شود، همان رنگهای متداول jQuery Validator ظاهر میشوند و کل ردیف همانند روشهای متداول Twitter bootstrap دارای رنگ قرمز انتساب یافته توسط کلاس error نخواهد شد.
برای رفع این مشکل باید اندکی اسکریپت نویسی کرد:
@section javaScript { <script type="text/javascript"> $.validator.setDefaults({ highlight: function (element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).addClass(errorClass).removeClass(validClass); } else { $(element).addClass(errorClass).removeClass(validClass); $(element).closest('.control-group').removeClass('success').addClass('error'); } $(element).trigger('highlated'); }, unhighlight: function (element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).removeClass(errorClass).addClass(validClass); } else { $(element).removeClass(errorClass).addClass(validClass); $(element).closest('.control-group').removeClass('error').addClass('success'); } $(element).trigger('unhighlated'); } }); $(function () { $('form').each(function () { $(this).find('div.control-group').each(function () { if ($(this).find('span.field-validation-error').length > 0) { $(this).addClass('error'); } }); }); }); </script> }
اینبار در حالت اعتبار سنجی، به شکل ذیل خواهیم رسید:
و یا اگر کاربر فیلد را تکمیل کند، رنگ فیلد و ردیف تعیین اعتبار شده، سبز میشود:
و در حالت خطاهای سفارشی سمت سرور، پس از postback، شکل زیر نمایش داده میشود:
بررسی سیستم جدید گرید بوت استرپ 3
<div class="container"> <h4 class="alert alert-info">ایجاد فاصله بین ستونها</h4> <div class="row"> <div class="col-lg-3 col-sm-4 alert alert-danger"> ستون اول </div> <div class="col-lg-8 col-lg-offset-1 col-sm-7 col-sm-offset-1 alert alert-success"> ستون دوم </div> </div> <!-- end row --> </div>
ممکنه راهنمائی بفرمائید
پلاگین DataTables کتابخانه jQuery - قسمت سوم
زمانیکه من با Ajax , Jquery سطرهای دیتای جدول مورد نظر برای DataTable شدن را از سمت سرور ایجاد میکنم متاسفانه بار اول دیتاها رو نشون میده ولی Search نمیکنه و صفحه بندی هم نمیکنه و ... در ضمن کدهای مربوطه رو هم میگذارم . لطفا راهنمایی کنید که اگه خواستیم دیتاها را از سمت سرور بیاریم و کار بده باید چه کار کرد؟ مرسی
$(document).ready(function () { dataparam2 = "cmd=FillScope"; $.ajax({ url: "Default2.aspx", type: "POST", data: dataparam2, async: true, success: function (msg) { if (msg != '') { var data = eval("(" + msg + ")"); $("#tbodytblMain").html(''); for (var i = 0; i < data.length; i++) { $("#tbodytblMain").append( "<tr class='odd gradeX'>" + "<td style='width:200px'>" + data[i].T + "</td>" + "<td style='width:150px'>" + data[i].P + "</td>" + "<td>" + data[i].S + "</td>" + "<td>" + data[i].TP + "</td>" + "<td>" + data[i].Sp + "</td>" + "</tr>"); } } }, error: function (msg) { } }); $('#tblMain').dataTable(); });
if (Request["cmd"] == "FillScope") { string Val = "برخوار"; JavaScriptSerializer js = new JavaScriptSerializer(); string serText = ""; MUIDataClassesDataContext db = new MUIDataClassesDataContext(); var LST = (from x in db.tblProjectInfos where x.tblScope.xScopeName.Contains(Val) orderby x.tblScope.xScopeName select new { P = x.xPlace, S = x.tblScope.xScopeName, TP = x.tblProjectType.xProjectTypeName, Sp = x.tblStatus.xStatusName }); serText = js.Serialize(LST); Response.Write(serText); Response.End(); }
JQuery Plugins #2
فضای نام
(function( $ ){ $.fn.tooltip = function( options ) { // این }; $.fn.tooltipShow = function( ) { // تعریف }; $.fn.tooltipHide = function( ) { // بد است }; $.fn.tooltipUpdate = function( content ) { // ! }; })( jQuery );
(function( $ ){ var methods = { init : function( options ) { // این }, show : function( ) { // تعریف }, hide : function( ) { // خوب است }, update : function( content ) { // ! } }; $.fn.tooltip = function( method ) { // منطق تابع را از اینجا صدا زده ایم if ( methods[method] ) { return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof method === 'object' || ! method ) { return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + method + ' does not exist on jQuery.tooltip' ); } }; })( jQuery );
// تابع init صدا زده میشود $('div').tooltip();
// تابع update با پارامتر صدا زده میشود $('div').tooltip('update', 'This is the new tooltip content!');
(function( $ ){ var methods = { init : function( options ) { return this.each(function(){ $(window).bind('resize.tooltip', methods.reposition); }); }, destroy : function( ) { return this.each(function(){ $(window).unbind('.tooltip'); }) }, reposition : function( ) { // ... }, show : function( ) { // ... }, hide : function( ) { // ... }, update : function( content ) { // ... } }; $.fn.tooltip = function( method ) { if ( methods[method] ) { return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof method === 'object' || ! method ) { return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + method + ' does not exist on jQuery.tooltip' ); } }; })( jQuery );
$('#fun').tooltip(); // مدتی بعد... $('#fun').tooltip('destroy');
استفاده از منابع داده محلی
در ادامه مثالی را از نحوهی استفاده از یک منبع داده محلی جاوا اسکریپتی، مشاهده میکنید:
<script type="text/javascript"> $(function () { var cars = [ { "Year": 2000, "Make": "Hyundai", "Model": "Elantra" }, { "Year": 2001, "Make": "Hyundai", "Model": "Sonata" }, { "Year": 2002, "Make": "Toyota", "Model": "Corolla" }, { "Year": 2003, "Make": "Toyota", "Model": "Yaris" }, { "Year": 2004, "Make": "Honda", "Model": "CRV" }, { "Year": 2005, "Make": "Honda", "Model": "Accord" }, { "Year": 2000, "Make": "Honda", "Model": "Accord" }, { "Year": 2002, "Make": "Kia", "Model": "Sedona" }, { "Year": 2004, "Make": "Fiat", "Model": "One" }, { "Year": 2005, "Make": "BMW", "Model": "M3" }, { "Year": 2008, "Make": "BMW", "Model": "X5" } ]; var carsDataSource = new kendo.data.DataSource({ data: cars }); carsDataSource.read(); alert(carsDataSource.total()); }); </script>
ذکر new kendo.data.DataSource به تنهایی به معنای مقدار دهی اولیه است و در این حالت منبع داده مورد نظر، استفاده نخواهد شد. برای مثال اگر متد total آنرا جهت یافتن تعداد عناصر موجود در آن فراخوانی کنید، صفر را بازگشت میدهد. برای شروع به کار با آن، نیاز است ابتدا متد read را بر روی این منبع داده مقدار دهی شده، فراخوانی کرد.
استفاده از منابع داده راه دور
در برنامههای کاربردی، عموما نیاز است تا منبع داده را از یک وب سرور تامین کرد. در اینجا نحوهی خواندن اطلاعات JSON بازگشت داده شده از جستجوی توئیتر را مشاهده میکنید:
<script type="text/javascript"> $(function () { var twitterDataSource = new kendo.data.DataSource({ transport: { read: { url: "http://search.twitter.com/search.json", dataType: "jsonp", contentType: 'application/json; charset=utf-8', type: 'GET', data: { q: "#kendoui" } }, schema: { data: "results" } }, error: function (e) { alert(e.errorThrown.stack); } }); }); </script>
در قسمت schema مشخص میکنیم که اطلاعات JSON بازگشت داده شده توسط توئیتر، در فیلد results آن قرار دارد.
کار با منابع داده OData
علاوه بر فرمتهای یاد شده، Kendo UI DataSource امکان کار با اطلاعاتی از نوع OData را نیز دارا است که تنظیمات ابتدایی آن به صورت ذیل است:
<script type="text/javascript"> var moviesDataSource = new kendo.data.DataSource({ type: "odata", transport: { read: "http://demos.kendoui.com/service/Northwind.svc/Orders" }, error: function (e) { alert(e.errorThrown.stack); } }); }); </script>
یک مثال: دریافت اطلاعات از ASP.NET Web API
یک پروژهی جدید ASP.NET را آغاز کنید. تفاوتی نمیکند که Web forms باشد یا MVC؛ از این جهت که مباحث Web API در هر دو یکسان است.
سپس یک کنترلر جدید Web API را به نام ProductsController با محتوای زیر ایجاد کنید:
using System.Collections.Generic; using System.Web.Http; namespace KendoUI02 { public class Product { public int Id { set; get; } public string Name { set; get; } } public class ProductsController : ApiController { public IEnumerable<Product> Get() { var products = new List<Product>(); for (var i = 1; i <= 100; i++) { products.Add(new Product { Id = i, Name = "Product " + i }); } return products; } } }
در ادامه نیاز است تعریف مسیریابی ذیل نیز به فایل Global.asax.cs برنامه اضافه شود تا بتوان به آدرس api/products در سایت، دسترسی یافت:
using System; using System.Web.Http; using System.Web.Routing; namespace KendoUI02 { public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { RouteTable.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
در ادامه فایلی را به نام Index.html (یا در یک View و یا یک فایل aspx دلخواه)، محتوای ذیل را اضافه کنید:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>Kendo UI: Implemeting the Grid</title> <link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" /> <link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" /> <script src="js/jquery.min.js" type="text/javascript"></script> <script src="js/kendo.all.min.js" type="text/javascript"></script> </head> <body> <div id="report-grid"></div> <script type="text/javascript"> $(function () { var productsDataSource = new kendo.data.DataSource({ transport: { read: { url: "api/products", dataType: "json", contentType: 'application/json; charset=utf-8', type: 'GET' } }, error: function (e) { alert(e.errorThrown.stack); }, pageSize: 5, sort: { field: "Id", dir: "desc" } }); $("#report-grid").kendoGrid({ dataSource: productsDataSource, autoBind: true, scrollable: false, pageable: true, sortable: true, columns: [ { field: "Id", title: "#" }, { field: "Name", title: "Product" } ] }); }); </script> </body> </html>
- گرید صفحه، در محل div ایی با id مساوی report-grid تشکیل خواهد شد.
- سپس DataSource ایی که به آدرس api/products اشاره میکند، تعریف شده و در آخر productsDataSource را توسط یک kendoGrid نمایش دادهایم.
- نحوهی تعریف productsDataSource، در قسمت استفاده از منابع داده راه دور ابتدای بحث توضیح داده شد. در اینجا فقط دو خاصیت pageSize و sort نیز به آن اضافه شدهاند. این دو خاصیت بر روی نحوهی نمایش گرید نهایی تاثیر گذار هستند. pageSize تعداد رکورد هر صفحه را مشخص میکند و sort نحوهی مرتب سازی را بر اساس فیلد Id و در حالت نزولی قرار میدهد.
- در ادامه، ابتداییترین حالت کار با kendoGrid را ملاحظه میکنید.
- تنظیم dataSource و autoBind: true (حالت پیش فرض)، سبب خواهند شد تا به صورت خودکار، اطلاعات JSON از مسیر api/products خوانده شوند.
- سه خاصیت بعدی صفحه بندی و مرتب سازی خودکار ستونها را فعال میکنند.
- در آخر هم دو ستون گرید، بر اساس نامهای خواص کلاس Product تعریف شدهاند.
سورس کامل این قسمت را از اینجا میتوانید دریافت کنید:
KendoUI02.zip
ASP.NET MVC #21
@{ var postUrl = Url.Action(actionName: "Delete", controllerName: "Student"); } <div class="deleteDialog"> <div> آیتمهای انتخاب شده حذف خواهند شد. آیا تأیید میکنید؟ </div> <p> <input type="submit" id="btn_SubmitDelete" value="حذف" /> <input type="submit" id="btn_CancelDelete" value="انصراف" /> </p> </div> <script type="text/javascript"> $(function () { $("#btn_SubmitDelete").click(function (e) { var button = $(this); e.preventDefault(); var data = "1,3,8,9"; $.ajax({ type: "POST", url: "@postUrl", data: JSON.stringify({ ids: data}), contentType: "application/json; charset=utf-8", dataType: 'json', cache: false, beforeSend: function () { }, success: function (html) { alert(html); $(".deleteDialog").parent("div").css("display", "none"); }, complete: function () { button.removeAttr('disabled'); button.val("حذف"); } }); }); $("#btn_CancelDelete").click(function (e) { e.preventDefault(); var button = $(this); $(".deleteDialog").parent("div").css("display", "none"); }); }); </script>
[HttpGet] public ActionResult Delete() { return PartialView("Pv_Delete"); } [HttpPost] [AjaxOnly] public ActionResult Delete(string ids) { var allIds = ids.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList(); Thread.Sleep(2000); if (true) { return Json(new { result = "ok" }, JsonRequestBehavior.AllowGet); } return Json(new { result = "error" }); }
return Json( "test");
completeHandler: function (data) { alert(data) }
return Json( new { success = true, message = Resources.Global.Texts.Successful });
completeHandler: function (data) { alert(data.success) }
در این مجموعه مقالات، به بررسی و آموزش برنامه نویسی شیء گرا در جاوا اسکریپت میپردازیم. در طول آموزش، فرض را بر این قرار دادیم که شما به عنوان خوانندهی این مقاله، با مبانی جاوا اسکریپت آشنا میباشید و حداقل چند قطعه کد مفید را با جاوا اسکریپت نوشتهاید. همچنین کمی هم با مباحث شیء گرایی آشنا میباشید.
روال آموزش در این مجموعه به گونه است که در ابتدا به معرفی مباحث پیش نیاز جهت ورود به دنیای شیء گرایی در جاوا اسکریپت، پرداخته خواهد شد. سپس مباحث شیء گرایی را آغاز خواهیم نمود و تمامی نکات ریز و درشت آن را بررسی خواهیم کرد. پس از پایان این مقالات قادر خواهید بود تا تمامی کتابخانهها و Frameworkهای جاوا اسکریپتی را مطالعه نموده و به راحتی تکنیکهای کد نویسی آن را درک کنید. همچنین خود شما نیز برای نوشتن یک کتابخانه یا Framework جاوا اسکریپتی استاندارد و حرفهای، دست به کار شوید و یک کتابخانه سودمند را ارائه نمایید.
با چند مثال ساده و بصورت تقریبا مبتدی مسائل پایه را تشریح نموده و آرام آرام مباحث حرفه ای را آغاز خواهیم کرد. قرار است در پایان این آموزشها به بررسی الگوهای موجود در جاوا اسکریپت نیز بپردازم که مجموعه مقالات مربوط به الگوها را در قالب مجموعه مقالاتی مجزا ارائه مینمایم.
در تهیهی این مجموعه مقالات از منابع زیر استفاده شده است:
1. Pro JavaScript Techniques (John Resig ، خالق JQuery – فصول 2 و 3)
2. Professional JavaScript for Web Developers (Third Edition) (Nicholas C. Zakas – فصول 3، 4، 5، 6 و 7)
3. Object-Oriented JavaScript (Stoyan Stefanov – فصول 3، 4، 5، 6 و 8)
4. و تجربهی ناچیز اینجانب
توابع (Functions)
همیشه در برنامه، مجموعه دستوراتی وجود دارند که عمل خاصی را انجام میدهند و به دفعات نیز مورد استفاده قرار میگیرند. جهت جلوگیری از تکرار این دستورات، افزایش خوانایی و کاهش پیچیدگی برنامه، این دستورات را در بستهای به نام تابع قرار میدهیم تا در زمان نیاز، آن را فراخوانی یا اجرا نماییم. جهت تعریف تابع در جاوا اسکریپت به صورت زیر عمل مینماییم:
function <functionName> ([arg0, arg1, …, argN]) { <statements> }
به عنوان مثال:
function sayHello(name, message) { alert("Hello " + name + ", " + message); }
این تابع شامل دو آرگومان ورودی است که میتواند به صورت زیر فراخوانی شود:
sayHello("Meysam", "welcome to site");
خروجی این تابع “Hello Meysam, welcome to site” می باشد که به صورت یک پنجرهی پیغام، نمایش مییابد. تابع فوق هیچ مقداری را به عنوان خروجی به برنامهی اصلی یا محل فراخوانی خود بر نمیگرداند. اگر بخواهیم توسط تابع مقداری را برگردانیم میتوانیم از دستور return برای این منظور استفاده نماییم. به مثال زیر توجه کنید:
function sum(num1, num2) { return num1 + num2; }
تابع sum دو عدد را به عنوان آرگومان ورودی دریافت نموده و حاصل جمع آنها را توسط دستور return به عنوان خروجی بر میگرداند. تابع فوق را میتوان به صورت زیر فراخوانی نمود:
alert(sum(10, 20));
خروجی :
30
اینک به بررسی چند نکته در مورد دستور return میپردازیم. دستور return فقط میتواند یک مقدار را برگرداند و نمیتوان، چند مقدار را مقابل این دستور نوشت. همچنین روال اجرای تابع با رسیدن به دستور return خاتمه مییابد و دستورات بعد از آن اجرا نخواهند شد. به مثال زیر توجه کنید:
function sum(num1, num2) { return num1 + num2; alert("Hello"); }
در مثال فوق دستور alert به هیچ عنوان اجرا نخواهد شد؛ زیرا تابع با رسیدن به دستور return خاتمه مییابد. یک تابع میتواند شامل بیش از یک دستور return باشد.
function diff(num1,num2) { if (num1 > num2) return num1 - num2; else return num2 - num1; }
تابع فوق اختلاف دو عدد را بدست میآورد و اگر عدد اول بزرگتر باشد، عدد دوم را از عدد اول تفریق میکند؛ در غیر اینصورت عدد اول را از عدد دوم تفریق میکند و به عنوان خروجی بر میگرداند. نکتهی دیگری که لازم است بدانید این است که دستور return می تواند هیچ مقداری را بر نگرداند و به تنهایی بکار گرفته شود. در این صورت دقیقا بعد از دستور return سمی کالن (;) قرار میدهیم.
function checkNumber(num) { if (isNaN(num)) { alert("Not a number"); return; } alert(num+" is a number"); }
تابع فوق یک ورودی را دریافت مینماید و در صورتی که آرگومان ورودی عدد نباشد پیغام “Not a number” را نمایش میدهد و از تابع خارج میشود. در صورتی که آرگومان ورودی یک عدد باشد، پیغام دوم را نمایش میدهد.
توجه:
یک تابع بهتر است همیشه یک مقداری را به عنوان خروجی برگرداند و یا کلا هیچ مقداری را بر نگرداند. نوشتن توابعی که در برخی شرایط مقداری را به عنوان خروجی بر میگردانند و در برخی شرایط مقداری را برنمی گردانند موجب ایجاد پیچیدگی در اشکال زدایی میگردند. نوشتن تابعی به صورت زیر کمی گیج کننده و نامتعارف میباشد:
function sum(num1, num2) { if (isNaN(num1) || isNaN(num2)) return; // بهتر است حداقل مقدار 0 برگردانده شود return num1 + num2; }
کار با آرگومان ها
رفتار آرگومانها در جاوا اسکریپت نسبت به سایر زبانهای برنامه نویسی کاملا متفاوت میباشد. در جاوا اسکریپت تعداد و نوع آرگومانهای ارسالی بررسی نمیشوند و خطایی هم رخ نخواهد داد. به عنوان مثال اگر تابعی با 3 آرگومان ورودی دارید، میتوانید با 0 تا 3 آرگومان ورودی، آن تابع را فراخوانی نمایید. زیرا آرگومانها در سیستم داخلی جاوا اسکریپت به صورت یک آرایه ارسال میگردند و تابع توجه نمیکند که کدام آرگومانها به این آرایه ارسال شدهاند.
با توجه به قابلیتی که در مورد آرگومانها ذکر شد و به دلیل عدم مدیریت نوع و تعداد آرگومانهای ارسالی، مطمئنا جهت جلوگیری از بروز خطا در توابع، باید تعداد و نوع آرگومانهای ارسالی بررسی و مدیریت شوند. همچنین در هر تابع، آرایهای به نام arguments به صورت توکار تعبیه شده است که مدیریت آرگومانها را تسهیل میبخشد. به مثال زیر توجه کنید:
function sayHello() { alert("Hello " + arguments[0] + ", " + arguments[1]); } sayHello("Meysam", "welcome to site");
خروجی :
"Hello Meysam, welcome to site"
تابع فوق هیچ آرگومان ورودی ندارد ولی با دو آرگومان ورودی فراخوانی شده است. در داخل تابع توسط آرایه arguments به آرگومانهای ارسالی دسترسی پیدا کردیم. حال به مثال زیر توجه کنید:
function sum() { var s = 0; for (var i = 0; i < arguments.length; i++) s += arguments[i]; return s; } alert(sum()); alert(sum(10, 20, 30, 40, 50)); alert(sum(10));
خروجی :
0
150
10
در تابع فوق هیچ آرگومان ورودی وجود ندارد ولی این تابع را با 0، 5 و 1 آرگومان ورودی فراخوانی نمودیم. این تابع مجموع چند عدد را محاسبه و بر میگرداند و میتواند به تعداد نامحدودی عدد دریافت نماید. البته بهتر است نوع آرگومانهای ارسالی نیز بررسی شوند تا خطایی در محاسبات رخ ندهد. همچنین بجای حلقه for از حلقه for…in استفاده خواهم کرد.
function sum() { var s = 0; for (var i in arguments) { if (isNaN(arguments[i])) continue; s += arguments[i]; } return s; } alert(sum()); alert(sum(10, 20, "a", 40, 50)); alert(sum(10));
خروجی :
0
120
10
اگر دقت کرده باشید در فراخوانی دوم، رشته “a” به تابع ارسال شده است و چون آرگومانهای نامعتبر را مدیریت نمودهایم، خطایی در خروجی رخ نمیدهد. به مثال زیر نیز توجه نمایید:
function sum(a,b,c) { return a + b + c; } alert(sum(10, 20, 30)); alert(sum(10, 20)); alert(sum());
خروجی :
60
NaN
NaN
تابع فوق دارای 3 آرگومان ورودی میباشد؛ ولی ما این تابع را با 2 و 0 آرگومان ورودی فراخوانی نمودیم که خروجی نامناسبی را تولید نموده است. برای رفع این مشکل و معتبر سازی آرگومانهای ارسالی میتوانیم به صورت زیر عمل نماییم:
function sum(a, b, c) { if (isNaN(a)) a = 0; if (isNaN(b)) b = 0; if (isNaN(c)) c = 0; return a + b + c; } alert(sum(10, 20, 30)); alert(sum(10, 20)); alert(sum());
خروجی :
60
30
0
در تابع، قبل از انجام عمل محاسبه، بررسی کردیم که آرگومانهای ارسالی مقدار دهی شده باشند. در صورت عدم مقداردهی و یا مقداردهی نامناسب، آرگومان ارسالی را با صفر مقداردهی مینماید. اگر آرگومان مورد نظر به تابع ارسال نشود، مقدار پیش فرض آن undefined میباشد.
با توجه به مسائل مطرح شده در مورد توابع، این روش استفاده و کاربرد توابع، جزء معایب توابع در جاوا اسکریپت محسوب نمیشود. این تکنیک استفاده از توابع، موجب افزایش انعطاف پذیری توابع و آزادی عمل برنامه نویس میگردد که لذت بیشتری را به برنامه نویسی میدهد.
توجه:
به آرگومانهایی که در تابع دارای نام میباشند و یا به عبارتی، آرگومانهایی که نام آنها در تابع ذکر میشود، Named Arguments یا آرگومانهای نامی (اسمی و یا نامدار) میگویند. مثل آرگومان های a ، b وc در تابع sum .
عدم پشتیبانی از سربارگذاری یا Overloading
در زبانهای برنامه نویسی شیء گرا، امکان تعریف توابع هم نام وجود دارد؛ به شرطی که امضای این توابع با هم متفاوت باشند. منظور از امضاء، تعداد و نوع آرگومانهای ورودی میباشد. از آنجاییکه در سیستم داخلی جاوا اسکریپت، آرگومانها بصورت یک آرایه ارسال میشوند، بنابراین امضاء برای توابع مفهومی ندارد؛ پس نمیتوانیم توابع هم نام یا overloading داشته باشیم.
اگر دو تابع هم نام داشته باشیم، تابعی که دیرتر تعریف میشود، جایگزین تابع قبلی میگردد. به مثال زیر توجه کنید:
function calc(num1,num2) { return num1 + num2; } function calc(num1,num2) { return num1 - num2; } alert(calc(200,100));
خروجی :
100
همانطور که در مثال فوق مشاهده مینمایید، تابع دوم فراخوانی شدهاست و حاصل تفریق به عنوان خروجی نمایش یافته است.
فراخوانی Web API از طریق مرورگر
با فشردن کلید F5، پروژه را اجرا کنید. شکل ذیل ظاهر میشود.
صفحه ای که ظاهر میشود، یک View است که توسط HomeController و متد Index آن برگشت داده شده است. برای فراخوانی متدهای موجود در کلاس Controller مثال قسمت قبل که مربوط به Web API است، باید به یکی از آدرسهای اشاره شده در قسمت قبل برویم. به عنوان مثال، برای به دست آوردن لیست تمامی محصولات، به آدرس http://localhost:xxxx/api/products بروید. xxxx، شمارهی پورتی است که Web Server داخلی Visual Studio در هنگام اجرای پروژه به آن اختصاص میدهد. آن را نسبت به پروژهی خود تغییر دهید.
نتیجهی دریافتی بستگی به نوع مرورگری دارد که استفاده میکنید. Internet Explorer از شما در مورد باز کردن یا ذخیرهی فایلی با نام products پرسش میکند (شکل ذیل).
محتوای فایل، بدنهی پاسخ دریافتی است. اگر این فایل را باز کنید، خواهید دید که که محتوای آن، لیستی از محصولات با فرمت JSON مانند ذیل است.
[{"Id":1,"Name":"Tomato soup","Category":"Groceries","Price":1.39},{"Id":2,"Name": "Yo-yo","Category":"Toys","Price":3.75},{"Id":3,"Name":"Hammer","Category": "Hardware","Price":16.99}]
دلیل تفاوت در نتیجهی دریافتی این است که مرورگر Internet Explorer و Firefox، هر یک مقدار متفاوتی را در هدر Accept درخواست، ارسال میکنند. بنابراین، Web API نیز مقدار متفاوتی را در پاسخ برگشت میدهد.
حال به آدرسهای ذیل بروید:
http://localhost:xxxx/api/products/1
http://localhost:xxxx/api/products?category=hardware
اولین آدرس، باید محصولی با مشخصهی 1 را برگشت دهد و دومین آدرس، لیستی از تمامی محصولاتی که در دستهی hardware قرار دارند را برگشت میدهد (در مثال ما فقط یک آیتم این شرط را دارد).
نکته: در صورتی که در هنگام فراخوانی هر یک از متدهای Web API با خطای ذیل مواجه شدید، دستور [("AcceptVerbs("GET", "POST] را به ابتدای متدها اضافه کنید.
The requested resource does not support http method 'GET'
فراخوانی Web API با استفاده از کتابخانهی jQuery
در قسمت قبل، متدهای Web API را مستقیماً از طریق وارد کردن آدرس آنها در نوار آدرس مرورگر فراخوانی کردیم. اما در اکثر اوقات، این متدها با روشهای برنامه نویسی توسط یک Client فراخوانی میشوند. اجازه بدهید Clientیی ایجاد کنیم که با استفاده از jQuery، متدهای ما را فراخوانی میکند.
در Solution Explorer، از پوشهی Views و سپس Home، فایل Index.cshtml را باز کنید.
تمامی محتویات این View را حذف و کدهای ذیل را در آن قرار دهید.
<!DOCTYPE html> <html> <head> <title>ASP.NET Web API</title> <script src="../../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> </head> <body> <div> <h1>All Products</h1> <ul id='products' /> </div> <div> <label for="prodId">ID:</label> <input type="text" id="prodId" size="5"/> <input type="button" value="Search" onclick="find();" /> <p id="product" /> </div> </body> </html>
بازیابی لیستی از محصولات
برای بازیابی لیستی از محصولات، فقط کافی است تا یک درخواست از نوع GET به آدرس "/api/products" بفرستید. این کار با jQuery به صورت ذیل انجام میشود.
<script type="text/javascript"> $(document).ready(function () { // Send an AJAX request $.getJSON("api/products/", function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, val) { // Format the text to display. var str = val.Name + ': $' + val.Price; // Add a list item for the product. $('<li/>', { html: str }) .appendTo($('#products')); }); }); }); </script>
متد getJSON، یک درخواست AJAX از نوع GET را ارسال میکند و پاسخ دریافتی آن نیز با فرمت JSON خواهد بود. دومین پارامتر متد getJSON، یک callback است که پس از دریافت موفقیت آمیز پاسخ اجرا میشود.
بازیابی یک محصول با استفاده از مشخصهی آن
برای بازیابی یک محصول با استفاده از مشخصهی آن، یک درخواست از نوع GET به آدرس "api/products/id/" ارسال کنید. id، مشخصهی محصول است. کد ذیل را در ادامهی کد قبل و پیش از تگ <script/> قرار دهید.
function find() { var id = $('#prodId').val(); $.getJSON("api/products/" + id, function (data) { var str = data.Name + ': $' + data.Price; $('#product').html(str); }) .fail( function (jqXHR, textStatus, err) { $('#product').html('Error: ' + err); }); }
باز هم از متد getJSON استفاده کردیم، اما این بار مقدار id برای آدرس از یک Text Box خوانده و آدرس ایجاد میشود. پاسخ دریافتی، یک محصول در قالب JSON است.
اجرای پروژه
پروژه را با فشردن کلید F5 اجرا کنید. پس از نمایش فرم، تمامی محصولات بر روی صفحه نمایش داده میشوند. عدد 1 را وارد و بر روی دکمهی Search کلیک کنید، محصولی که مشخصهی آن 1 است نمایش داده میشود (شکل ذیل).
اگر مشخصه ای را وارد کنید که وجود ندارد، خطای 404 با مضمون "Error: Not Found" بر روی صفحه نمایش داده میشود و در صورتی که به جای عدد، عبارتی غیر عددی وارد کنید، خطای 400 با مضمون: "Error: Bad Request" نمایش داده میشود. در Web API، تمامی پاسخها باید در قالب کدهای وضعیت HTTP باشند (شکل ذیل). این یکی از اصول اساسی کار با وب سرویسها است. وفادار ماندن به مفاهیم پایهی وب، دید بهتری در مورد اتفاقاتی که میافتد به شما میدهد.
در قسمت بعد با مفهوم مسیریابی در ASP.NET Web API آشنا میشوید.