مطالب
آشنایی با مفاهیم شیء گرایی در جاوا اسکریپت #2
از آنجا که برای کار با جاوا اسکریپت نیاز به درک کاملی درباره‌ی مفهوم حوزه کارکرد متغیرها (Scope) می‌باشد و نحوه فراخوانی توابع نیز نقش اساسی در این مورد بازی می‌کند، در این قسمت با این موارد آشنا خواهیم شد:
جاوا اسکریپت از مفهومی به نام functional scope برای تعیین حوزه متغیرها استفاده می‌کند و به این معنی است که با تعریف توابع، حوزه عملکرد متغیر مشخص می‌شود. در واقع هر متغیری که در یک تابع تعریف می‌شود در کلیه قسمتهای آن تابع، از قبیل If statement – for loops و حتی nested function نیز در دسترس میباشد.
اجازه دهید با مثالی این موضوع را بررسی نماییم.
function testScope() {
var myTest = true;
if (true) {
var myTest = "I am changed!"
}
alert(myTest);
}
testScope(); // will alert "I am changed!"
همانگونه که میبینیم با اینکه در داخل بلاک if یک متغیر جدید تعریف شده، ولی در خارج از این بلاک نیز این متغیر قابل دسترسی میباشد. البته در مثال بالا اگر بخواهیم به متغیر myTest در خارج از function دسترسی داشته باشیم، با خطای undefined مواجه خواهیم شد. یعنی برای مثال در کد زیر:
function testScope() {
var myTest = true;
if (true) {
var myTest = "I am changed!"
}
alert(myTest);
}
testScope(); // will alert "I am changed!"
alert(myTest); // will throw a reference error, because it doesn't exist outside of the function
 برای حل این مشکل دو راه وجود دارد: 
1 – متغیر myTest را در بیرون بلاک testScope() تعریف کنیم
2 – هنگام تعریف متغیر myTest، کلمه کلیدی var را حذف کنیم که این موضوع باعث میشود این متغیر در کل window قابل دسترس باشد و یا به عبارتی متغیر global میشود.
قبل از پرداختن به ادامه بحث خواندن مقاله مربوط به Closure در جاوااسکریپت توصیه میگردد .
در پایان بحث Scope‌ها با یک مثال نسبتا جامع اکثر این حالات به همراه خروجی را نشان میدهیم :
<script type="text/javascript">
          // a globally-scoped variable
        var a = 1;
        // global scope
        function one()
        {
            alert(a);
        }
        // local scope
        function two(a)
        {
            alert(a);
        }
        // local scope again
        function three()
        {
            var a = 3;
            alert(a);
        }
        // Intermediate: no such thing as block scope in javascript
        function four()
        {
            if (true)
            {
                var a = 4;
            }
            alert(a); // alerts '4', not the global value of '1'
        }
        // Intermediate: object properties
        function Five()
        {
            this.a = 5;
        }
        // Advanced: closure
        var six = function ()
        {
            var foo = 6;
            return function ()
            {
                // javascript "closure" means I have access to foo in here, 
                // because it is defined in the function in which I was defined.
                alert(foo);
            }
        }()
        // Advanced: prototype-based scope resolution
        function Seven()
        {
            this.a = 7;
        }
        // [object].prototype.property loses to [object].property in the lookup chain
        Seven.prototype.a = -1; // won't get reached, because 'a' is set in the constructor above.
        Seven.prototype.b = 8; // Will get reached, even though 'b' is NOT set in the constructor.
        // These will print 1-8
        one();
        two(2);
        three();
        four();
        alert(new Five().a);
        six();
        alert(new Seven().a);
        alert(new Seven().b);
</Script>
برای مطالعه بیشتر به اینجا  مراجعه نمایید.

Function Invocation Patterns In JavaScript :
از آنجا که توابع در جاوااسکریپت به منظور 1 – ساخت اشیاء  و 2 – حوزه دسترسی متغیرها(Scope)  نقش اساسی ایفا می‌کنند بهتر است کمی درباره استفاده و نحوه فراخوانی آنها  (Function Invocation Patterns) در جاوااسکریپت بحث نماییم.
در جاوااسکریپت 4 مدل فراخوانی تابع داریم که به نامهای زیر مطرح هستند:
1. Method Invocation
2. Function Invocation
3. Constructor Invocation
4. Apply And Call Invocation
 در فراخوانی توابع به هر یک از روشهای بالا باید به این نکته توجه داشت که حوزه دسترسی متغیرها در جاوااسکریپت ابتدا و انتهای توابع هستند و اگر به عنوان مثال از توابع تو در تو استفاده کردیم ،حوزه شی this برای توابع داخلی تغییر خواهد کرد .این موضوع را در طی مثالهایی نشان خواهیم داد.
Method Invocation :
وقتی یک تابع قسمتی از یک شی باشد به آن متد میگوییم به عنوان مثال :
var obj = {
    value: 0,
    increment: function() {
        this.value+=1;
    }
};
obj.increment(); //Method invocation
در اینحالت this به شی (Object) اشاره میکند که متد در آن فراخوانی شده است و در زمان اجرا نیز به عناصر شی Bind میشود ،در مثال بالا حوزه  this شی obj خواهد شد و به همین منظور به متغیر value دسترسی داریم.
Function Invocation:
در اینحالت که از () برای فراخوانی تابع استفاده میگردد ،This به شی سراسری (global object ) اشاره می‌کند؛ منظور اینکه this به اجزای تابعی که فراخوانی آن انجام شده اشاره نمی‌کند. اجازه دهید با مثالی این موضوع را روشن کنیم
<script type="text/javascript">
var value = 500; //Global variable
var obj = {
    value: 0,
    increment: function() {
        this.value++;
        var innerFunction = function() {
            alert(this.value);
        }
        innerFunction(); //Function invocation pattern
    }
}
obj.increment(); //Method invocation pattern
<script type="text/javascript">
Result : 500
از آنجا که  () innerFunction به شکل  Function invocation pattern فراخوانی شده است به متغیر value در داخل تابع increment دسترسی نداریم و حوزه دسترسی global میشود و اگر در حوزه global نیز این متغیر تعریف نشده بود به خطای undefined میرسیدیم .
برای حل این گونه مشکلات ساختار کد نویسی ما بایستی به شکل زیر باشد :
<script type="text/javascript">
var value = 500; //Global variable
var obj = {
    value: 0,
    increment: function() {
        var that = this;
        that.value++;
        var innerFunction = function() {
            alert(that.value);
        }
        innerFunction(); //Function invocation pattern
    }
}
obj.increment();
<script type="text/javascript">
Result : 1
در واقع با تعریف یک متغیر با نام مثلا that و انتساب شی  this به آن میتوان در توابع بعدی که به شکل   Function invocation pattern فراخوانی میگردند به این متغیر دسترسی داشت .
Constructor Invocation :
در این روش برای فراخوانی تابع از کلمه new استفاده میکنیم. در این حالت یک شیء مجزا ایجاد شده و به متغیر دلخواه ما اختصاص پیدا می‌کند. به عنوان مثال داریم :
 var Dog = function(name) {   
  //this == brand new object ({});    
    this.name = name;    
    this.age = (Math.random() * 5) + 1;
};
var myDog = new Dog('Spike');
//myDog.name == 'Spike'
//myDog.age == 2
var yourDog = new Dog('Spot');
//yourDog.name == 'Spot'
//yourDog.age == 4
در این مورد با استفاده از New باعث میشویم همه خواص و متدهای تابع function برای هر نمونه از آن که ساخته میشود ( از طریق مفهوم Prototype که قبلا درباره آن بحث شد) بطور مجزا اختصاص یابد. در مثال بالا شی mydog چون حاوی یک نمونه از تابع dog بصورت  Constructor Invocation میباشد، در نتیجه به خواص تابع dog از قبیل name  و age دسترسی داریم. در اینجا اگر کلمه new استفاده نشود به این خواص دسترسی نداریم؛ در واقع با اینکار، this به mydog اختصاص پیدا میکند.
اگر از new استفاده نشود متغیر myDog ،undefined میشود.
یک مثال دیگر :
var createCallBack = function(init) { //First function
    return new function() { //Second function by Constructor Invocation
        var that = this;
        this.message = init;
        return function() { //Third function
            alert(that.message);
        }
    }
}
window.addEventListener('load', createCallBack("First Message"));
window.addEventListener('load', createCallBack("Second Message"));
در مثال بالا از مفهوم closure  نیز در مثالمان استفاده کرده ایم .
Apply And Call Invocation:
تمامی توابع جاوااسکریپت دارای دو متد توکار apply() و call() هستند که توسط این متدها میتوان این توابع را با context دلخواه فراخوانی کرد.
نحوه فراخوانی به شکل مقابل است :
myFunction.apply(thisContext, arrArgs);
myFunction.call(thisContext, arg1, arg2, arg3, ..., argN);
که thisContext به حوزه اجرایی (execution context) تابع اشاره میکند. تفاوت دو متد apply() و call() در نحوه فرستادن آرگومانها به تابع میباشد که در اولی توسط آرایه اینکار انجام میشود و در دومی همه آرگومانها را بطور صریح نوشته و با کاما از هم جدا میکنیم .
مثال :
var contextObject = {
testContext: 10
}
var otherContextObject = {
testContext: "Hello World!"
}
var testContext = 15; // Global variable
function testFunction() {
alert(this.testContext);
}
testFunction(); // This will alert 15
testFunction.call(contextObject); // Will alert 10
testFunction.apply(otherContextObject); // Will alert "Hello World”
در این مثال دو شی متفاوت با خواص همنام تعریف کرده و یک متغیر global نیز تعریف میکنیم. در انتها یک تابع تعریف میکنیم که مقدار this.testContext را نمایش میدهد. در ابتدا حوزه اجرایی تابع (this) کل window جاری میباشد و وقتی testFunction() اجرا شود مقدار متغیر global نمایش داده میشود. در اجرای دوم this به contextObject اشاره کرده و حوزه اجرایی عوض میشود و در نتیجه مقدار testContext مربوطه که در این حالت 10 میباشد نمایش داده میشود و برای فراخوانی سوم نیز به همین شکل .
یک مثال کاملتر :
var o = {
  i : 0,
  F : function() {
    var a = function() { this.i = 42; };
    a();
    document.write(this.i);
  }
};
o.F();
Result :0
خط o.f() تابع f را به شکل Method invocation اجرا میکند. در داخل تابع f یک تابع دیگر به شکل function invocation اجرا میشود که در اینحال this به global object اشاره میکند و باعث میشود مقدار i در خروجی 0 چاپ شود .
برای حل این مشکل 2 راه وجود دارد  
راه اول :
var p = {
  i : 0,
  F : function() {
    var a = function() { this.i = 42; };
    a.apply(this);
    document.write(this.i);
  }
};
 p.F();
Result :42
با اینکار this را موقع اجرای تابع درونی برایش فرستاده تا حوزه اجرای تابع عوض شود و به i دسترسی پیدا کنیم .
یا اینکه همانند مثالهای قبلی :
var q = {
  i: 0,
  F: function F() {
    var that = this;
    var a = function () {
      that.i = 42;
    }
    a();
    document.write(this.i);
  }
}
 q.F();

منابع :
Javascript programmer,s refrence
 
مطالب
Ajax.BeginForm و ارسال فایل به سرور در ASP.NET MVC
Ajax.BeginForm در ASP.NET MVC از jQuery Ajax برای ارسال مقادیر فرم، به سرور استفاده می‌کند. در این بین اگر یکی از عناصر فرم، المان ارسال فایل به سرور باشد، مقدار دریافتی در سمت سرور نال خواهد بود. مشکل اینجا است که نمی‌توان به کمک Ajax معمولی (یا به عبارتی XMLHttpRequest) فایلی را به سرور ارسال کرد. یا باید از سیلورلایت یا فلش استفاده نمود و یا از مرورگرهایی که XMLHttpRequest Level 2 را پشتیبانی می‌کنند (از IE 10 به بعد مثلا) که امکان Ajax upload توکار به همراه گزارش درصد آپلود را بدون نیاز به فلش یا سیلورلایت، دارند.
در این بین راه حل دیگری نیز وجود دارد که با تمام مرورگرها سازگار است؛ اما تنها گزارش درصد آپلود را توسط آن نخواهیم داشت. در اینجا به صورت پویا یک IFrame مخفی در صفحه تشکیل می‌شود، مقادیر معمولی فرم (تمام المان‌ها، منهای file) به صورت Ajax ایی به سرور ارسال خواهند شد. المان file آن در این IFrame مخفی، به صورت معمولی به سرور Postback می‌شود. البته کاربر در این بین چیزی را مشاهده یا احساس نخواهد کرد و تمام عملیات از دیدگاه او Ajax ایی به نظر می‌رسد. برای انجام اینکار تنها کافی است از افزونه‌ی AjaxFileUpload استفاده کنیم که در ادامه نحوه‌ی استفاده از آن‌را بررسی خواهیم کرد.


پیشنیازها

در ادامه فرض بر این است که افزونه‌ی AjaxFileUpload را دریافت کرده و به فایل Layout برنامه افزوده‌اید:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <div>
        @RenderBody()
    </div>

    <script src="~/Scripts/jquery-1.11.1.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
    <script src="~/Scripts/ajaxfileupload.js"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>


مدل، کنترلر و View برنامه

مدل برنامه مشخصات یک محصول است:
namespace MVCAjaxFormUpload.Models
{
    public class Product
    {
        public int Id { set; get; }
        public string Name { set; get; }
    }
}

کنترلر آن از سه متد تشکیل شده‌است:
using System.Threading;
using System.Web;
using System.Web.Mvc;
using MVCAjaxFormUpload.Models;

namespace MVCAjaxFormUpload.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(Product product)
        {
            var isAjax = this.Request.IsAjaxRequest();

            return Json(new { result = "ok" }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult UploadFiles(HttpPostedFileBase image1, int id)
        {
            var isAjax = this.Request.IsAjaxRequest();
            Thread.Sleep(3000); //شبیه سازی عملیات طولانی
            return Json(new { FileName = "/Uploads/filename.ext" }, "text/html", JsonRequestBehavior.AllowGet);
        }
    }
}
Index اول، کار نمایش صفحه‌ی ارسال اطلاعات را انجام خواهد داد.
Index دوم کار پردازش Ajax ایی اطلاعات ارسالی به سرور را به عهده دارد. HttpPost آن Ajax ایی است.
متد UploadFiles، کار پردازش اطلاعات ارسالی از طرف IFrame مخفی را انجام می‌دهد. HttpPost آن معمولی است.

و کدهای View این مثال نیز به شرح زیر است:
@model MVCAjaxFormUpload.Models.Product
@{
    ViewBag.Title = "Index";
}

<h2>Ajax Form Upload</h2>

@using (Ajax.BeginForm(actionName: "Index",
                       controllerName: "Home",
                       ajaxOptions: new AjaxOptions { HttpMethod = "POST" },
                       routeValues: null,
                       htmlAttributes: new { id = "uploadForm" }))
{
    <label>Name:</label>
    @Html.TextBoxFor(model => model.Name)
    <br />
    <label>Image:</label>
    <br />
    <input type="file" name="Image1" id="Image1" />
    <br />
    <input type="submit" value="Submit" />
    <img id="loading" src="~/Content/Images/loading.gif" style="display:none;">
}

@section Scripts
{
    <script type="text/javascript">
        $(function () {
            $('#uploadForm').submit(function () {
                $("#loading").show();
                $.ajaxFileUpload({
                    url: "@Url.Action("UploadFiles", "Home")", // مسیری که باید فایل به آن ارسال شود
                    secureuri: false,
                    fileElementId: 'Image1', // آی دی المان ورودی فایل
                    dataType: 'json',
                    data: { id: 1, data: 'test' }, // اطلاعات اضافی در صورت نیاز
                    success: function (data, status) {
                        $("#loading").hide();
                        if (typeof (data.FileName) != 'undefined') {
                            alert(data.FileName);
                        }
                    },
                    error: function (data, status, e) {
                        $("#loading").hide();
                        alert(e);
                    }
                });
            });
        });
    </script>
}
فرمی که توسط Ajax.BeginForm تشکیل شده‌است، یک فرم معمولی Ajax ایی است و نکته‌ی جدیدی ندارد. تنها در آن یک المان ارسال فایل قرار گرفته‌است و همچنین Id آن‌را نیز جهت استفاده توسط jQuery مشخص کرده‌ایم.
در ادامه نحوه‌ی فعال سازی ajaxFileUpload را دقیقا در زمان submit فرم، مشاهده می‌کنید. در اینجا url آن به اکشن متدی که اطلاعات المان file را باید دریافت کند، اشاره می‌کند. fileElementId آن مساوی Id المان فایل فرم Ajax ایی صفحه‌است. از قسمت data جهت ارسال اطلاعات اضافه‌تری به اکشن متد UploadFiles استفاده می‌شود. سایر قسمت‌های آن نیز مشخص هستند. اگر عملیات موفقیت آمیز بود، success آن و اگر خیر، error آن اجرا می‌شوند.
فقط باید دقت داشت که content type دریافتی توسط آن باید text/html باشد، که این مورد در اکشن متدهای کنترلر مشخص هستند.
به این ترتیب دیگر کاربر نیازی ندارد ابتدا یکبار بر روی دکمه‌ی دومی کلیک کرده و فایل را ارسال کند و سپس بار دیگر بر روی دکمه‌ی submit فرم کلیک نماید. هر دو کار توسط یک دکمه انجام می‌شوند.

کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید
MVCAjaxFormUpload.zip
مطالب
برنامه نویسی پیشرفته JavaScript - قسمت 3 - انواع ارجاعی و نحوه‌ی ایجاد اشیاء

انواع ارجاعی

قبلا در مورد مقادیر ارجاعی صحبت کردیم. در اینجا نیز به این موضوع اشاره می‌کنیم که هر مقدار ارجاعی، نمونه‌ای ایجاد شده از یک نوع ارجاعی می‌باشد. انواع ارجاعی در واقع ساختارهایی هستند که جهت گروه بندی داده‌ها و عملکرد بین آنها استفاده می‌شوند. در سایر زبان‌های برنامه نویسی شیء گرا، به انواع ارجاعی، کلاس و به مقادیر ارجاعی، شیء می‌گویند. در جاوا اسکریپت نیز، به مقادیر ارجاعی و یا نمونه‌های ایجاد شده از انواع ارجاعی، شیء می‌گویند. به انواع ارجاعی، توصیف گر شیء نیز می‌گویند؛ زیرا ویژگی‌ها و متدهای آن شیء را معرفی و توصیف می‌نماید.


نحوه‌ی ایجاد شیء از نوع ارجاعی Object

از آنجاییکه نوع ارجاعی Object هیچ ویژگی و متد خاصی ندارد، متداول‌ترین نوع ارجاعی جهت ایجاد اشیاء سفارشی می‌باشد. به دو روش می‌توان نمونه‌ای را از یک Object ایجاد نمود. روش اول استفاده از عملگر new و بصورت زیر می‌باشد:

var person = new Object ();
person . name = "Meysam" ;
person . age = 32 ;

با استفاده از عملگر new، شیء person را از نوع Object ایجاد نمودیم که شامل دو ویژگی (Property) به نام‌های name و age می‌باشد. در واقع شیء person ساختاری را جهت نگهداری اطلاعات یک شخص معرفی می‌کند. این عمل موجب جلوگیری از پراکندگی تعریف متغیرها و گروه بندی آنها در قالب یک شیء می‌شود. روش دوم استفاده از Object Literal Notation یا نماد تحت الفظی شیء و بصورت زیر می‌باشد:

var person = {
    name : "Meysam" ,
    age : 32
};

Object Literal Notation ، دستور میانبری برای ایجاد یک شیء از نوع Object می‌باشد. در مثال فوق هم، همانند روش اول، شیء person را با دو ویژگی name و age ایجاد نمود‌ه‌ایم. در این روش، نام ویژگی‌ها می‌توانند به صورت رشته‌ای و عددی نیز به یک شیء اختصاص یابد.

var person = {
    "name" : "Meysam" ,
    "age" : 32
};

معمولا از دو روش فوق زمانی استفاده می‌شود که می‌خواهیم اشیایی را ایجاد نماییم که ویژگی‌های آن‌ها فقط خواندنی باشند. با استفاده از روش دوم، حتی می‌توان یک شیء خالی را ایجاد نمود که در ابتدا هیچ ویژگی ای ندارد  و در مراحل بعد، ویژگی‌هایی را به آن اضافه نمود.

var person = {}; // var person = new Object();
person . name = "Meysam" ;
person . age = 32 ;

در مثال فوق شیء person بدون ویژگی‌ها تعریف شده است؛ سپس به آن ویژگی‌هایی را اضافه نموده‌ایم.

استفاده از روش Object Literal Notation ، یکی از روش‌های محبوب برنامه نویسان جاوا اسکریپت می‌باشد. زیرا با کمترین کد و بصورت بصری، شیء ای را ایجاد نموده و مثلا به یک متد ارسال می‌نمایند. به مثال زیر توجه کنید:

function displayInfo ( arg ) {
    var output = "" ;
    if ( arg . name != undefined )
        output += "Name: " + arg . name + "\n" ;
    if ( arg . age != undefined )
        output += "Age: " + arg . age + "\n" ;
    return output ;
}

alert (displayInfo ({
    name : "Meysam" ,
    age : 32
}));

alert (displayInfo ({
    name : "Sohrab"
}));

در این مثال یک تابع تعریف شده است که آرگومان ورودی آن یک شیء می‌باشد. در تابع بررسی می‌شود که اگر ویژگی name و یا age برای این آرگومان تعریف شده بود، خروجی تابع را تولید نماید. در واقع این ویژگی‌ها اختیاری می‌باشند و می‌توانند ارسال نگردند. در زمان فراخوانی تابع نیز شیء ای را بصورت Object Literal Notation ایجاد نموده و به تابع ارسال کردیم.

این الگو برای ارسال آرگومان، زمانی استفاده می‌شود که تعداد زیادی آرگومان اختیاری داریم و می‌خواهیم به تابع ارسال نماییم. معمولا کار با آرگومان‌های نامی (Named Arguments) راحت‌تر است ولی زمانیکه تعداد آرگومان‌های اختیاری زیاد باشند، مدیریت و نگهداری آنها سخت و طاقت فرسا می‌گردد و ظاهر زشتی را به تابع می‌دهد. بهترین راهکار جهت مدیریت چنین شرایطی این است که آرگومان‌های اجباری را به صورت آرگومان‌های نامی تعریف کنیم و آرگومان‌های اختیاری را به صورت یک شیء به تابع ارسال کنیم.

نکته‌ی دیگری که باید به آن توجه نمود این است که جهت دسترسی به ویژگی‌های یک شیء از (.) استفاده می‌شود. همچنین می‌توان به یک ویژگی با استفاده از [] و بصورت یک آرایه دسترسی داشت که در این صورت نام ویژگی بصورت رشته‌ای در [] ذکر خواهد شد.

alert ( person . name );
alert ( person [ "name" ]);

در عمل تفاوتی بین دو مورد فوق وجود ندارد. مهمترین مزیت استفاده از [] این است که می‌توانید توسط یک متغیر به ویژگی‌های یک شیء دسترسی داشته باشید. همچنین اگر نام ویژگی شامل کاراکترهایی باشد که خطای گرامری رخ می‌دهد یا از اسامی رزرو شده استفاده کرده باشید، می‌توانید از [] جهت دسترسی به ویژگی استفاده نمایید.

var propertyName = "name" ;
alert ( person [ propertyName ]);
alert ( person [ "first name" ]);

در دستور alert اول، با استفاده از یک متغیر به ویژگی name از شیء person دسترسی پیدا نمودیم. در دستور آخر نیز، به دلیل وجود space در نام ویژگی، مجبور هستیم جهت دسترسی به ویژگی first name از [] استفاده نماییم.


بررسی نوع ارجاعی Function

توابع در واقع یک شیء و نمونه‌ای از نوع ارجاعی Function می‌باشند که می‌توانند همانند سایر اشیاء ویژگی‌ها و متدهای خاص خود را داشته باشند. بنابراین می‌توان در یک عبارت، تابعی را به یک شیء نسبت داد. به مثال زیر توجه کنید:

var sum = function ( a , b ) {
    return a + b ;
};

alert ( sum ( 10 , 20 ));

خروجی :

    30


شیء sum را تعریف نموده و یک تابع را به آن اختصاص دادیم که شامل دو آرگومان ورودی می‌باشد. حال می‌توان با شیء sum همانند یک تابع رفتار نمود و تابع مورد نظر را فراخوانی کرد. توجه داشته باشید که هیچ نامی را در زمان تعریف تابع به آن اختصاص نداده‌ایم. به این شکل تعریف تابع، Function Expression می‌گویند.

همانند سایر اشیاء، نام تابع نیز اشاره‌گری به تابع می‌باشد. بنابراین می‌توان توابع را نیز به یکدیگر نسبت داد. به مثال زیر توجه کنید:

function sum ( a , b ) {
    return a + b ;
}
alert ( sum ( 10 , 10 ));

var anotherSum = sum ;
alert ( anotherSum ( 10 , 10 ));

sum = null ;
alert ( anotherSum ( 10 , 10 ));
alert ( sum ( 10 , 10 )); // Error: Object is not a function;

خروجی :

    20

    20

    20

    Error: Object is not a function


ابتدا تابعی را به نام sum ایجاد نمودیم که دو عدد را با هم جمع می‌کند. دقت داشته باشید که به این شکل تعریف تابع sum ، اعلان تابع یا Function Declaration می‌گویند. سپس متغیری را به نام anotherSum ، تعریف نموده و sum را به آن نسبت دادیم. توجه داشته باشید که در زمان انتساب یک تابع به یک متغیر نباید () را ذکر کنیم، زیرا ذکر () به منزله‌ی فراخوانی تابع و اختصاص خروجی آن به متغیر می‌باشد و نه انتساب اشاره گر تابع به آن متغیر. فراخوانی sum و anotherSum خروجی یکسانی را دارند؛ زیرا هر دو به یک تابع اشاره می‌کنند. در خطوط بعدی، شیء sum را با مقدار null تنظیم نمودیم. در واقع با این کار اشاره‌گر sum برابر null شده است؛ یعنی دیگر به هیچ تابعی اشاره نمی‌کند. ولی تابع همچنان در حافظه وجود دارد؛ زیرا اشاره‌گر دیگری به نام anotherSum در حال اشاره نمودن به آن می‌باشد. در مرحله‌ی بعدی که sum را فراخوانی نمودیم، به دلیل null بودن آن، خطا رخ خواهد داد.


بازنگری مجدد به مبحث Overloading

در اینجا فقط می‌خواهیم اشاره‌ای کنیم به مبحث Overloading که قبلا در مورد آن بحث کردیم تا دلیل فنی عدم وجود Overloading را در جاوا اسکریپت درک کنیم. همانطور که قبلا بیان شد، نام تابع در واقع اشاره گری به تابع می‌باشد؛ بنابراین تعریف دو تابع هم نام، همانند اختصاص مجدد مقدار یا تغییر مقدار یک متغیر می‌باشد. به مثال زیر توجه کنید:

function calc ( num1 , num2 ) {
    return num1 + num2 ;
}

function calc ( num1 , num2 ) {
    return num1 - num2 ;
}

همانطور که پیشتر نیز عنوان شد، تابع دوم جایگزین تابع اول می‌گردد. در واقع تعریف فوق همانند تعریف زیر می‌باشد:

var calc = function ( num1 , num2 ) {
    return num1 + num2 ;
};

calc = function ( num1 , num2 ) {
    return num1 - num2 ;
};

همانطور که می‌بینید، ابتدا متغیری به نام calc تعریف شده‌است و با یک تابع مقداردهی اولیه شده است. سپس با تابع دوم مقداردهی مجدد گردیده است و دیگر به تابع قبلی اشاره نمی‌کند. بنابراین همیشه تابع آخر جایگزین توابع قبلی می‌گردد. 


Function Declaration در مقابل Function Expression

این دو روش تعریف و استفاده از توابع تقریبا مشابه هم می‌باشند و فقط یک تفاوت اصلی بین آنها وجود دارد و آن به نحوه‌ی رفتار موتور پردازشی جاوا اسکریپت بر می‌گردد. Function Declaration قبل از اینکه کدهای جاوا اسکریپت خوانده و اجرا شوند، خوانده شده و در دسترس خواهند بود؛ اما Function Expression تا زمانی که روال اجرای کد به این خط از کد نرسد، اجرا نخواهد شد و در دسترس نخواهد بود. به مثال Function Declaration زیر توجه کنید:

alert ( sum ( 10 , 20 ));

function sum ( a , b ) {
    return a + b ;
}

خروجی :

    30


قبل از اعلان تابع sum ، این تابع فراخوانی شده است؛ ولی هیچ خطایی رخ نمی‌دهد. زیرا قبل از اجرای دستورات، تابع sum خوانده و در دسترس خواهد بود. اما اگر تابع فوق بصورت Function Expression تعریف شده بود، خطا رخ می‌داد و برنامه اجرا نمی‌شد.

alert ( sum ( 10 , 20 )); // Error: undefined is not a function

var sum = function ( a , b ) {
    return a + b ;
};

خروجی :

    Error: undefined is not a function


همانطور که می‌بینید، در خط اول برنامه، خطای اجرایی رخ داده است. زیرا هنوز روال اجرایی برنامه به خط تعریف تابع sum نرسیده‌است. بنابراین تابع sum در دسترس نخواهد بود و فراخوانی آن موجب بروز خطا می‌گردد.


ارسال تابع به عنوان ورودی یا خروجی توابع دیگر

همانطور که قبلا بیان شد، نام تابع در واقع یک متغیر می‌باشد که به تابع مورد نظر اشاره می‌کند. بنابراین می‌توان همانند یک متغیر با آن رفتار نموده و به عنوان آرگومان ورودی و یا مقدار خروجی یک تابع آن را ارسال نمود. به مثال زیر توجه کنید:

function add ( a , b ) {
    return a + b ;
}

function mult ( a , b ) {
    return a * b ;
}

function calc ( a , b , fn ) {
    return a * b + fn ( a , b );
}

alert ( calc ( 10 , 20 , add ));
alert ( calc ( 10 , 20 , mult ));

خروجی :

    230

    400


دو تابع به نامهای add و mult با دو آرگومان ورودی تعریف شده‌اند که به ترتیب حاصل جمع و حاصل ضرب دو آرگومان را بر می‌گردانند. تابع calc نیز با 3 آرگومان ورودی تعریف شده‌است که قصد داریم برای آرگومان سوم یک تابع را ارسال نماییم. تابع calc در 2 مرحله فراخوانی شده‌است که در یک مرحله تابع add و در مرحله‌ی دیگر تابع mult به عنوان آرگومان ورودی ارسال شده‌اند. همانطور که از قبل می‌دانید، نام تابع اشاره‌گری به خود تابع می‌باشد. در تابع calc نیز با فراخوانی آرگومان fn در واقع داریم تابع ارسالی را فراخوانی می‌نماییم. حال به مثال زیر توجه کنید که یک تابع را به عنوان خروجی بر می‌گرداند:

function createFunction ( a , b ) {
    return function ( c ) {
        var d = ( a + b ) * c ;
        return d ;
    };
}

var fn = createFunction ( 10 , 20 );
alert ( fn ( 30 ));

خروجی :

    900


تابع createFunction دارای 2 آرگومان ورودی می‌باشد و یک تابع را با 1 آرگومان ورودی بر می‌گرداند. در ابتدا تابع createFunction را با آرگومان‌های 10 و 20 فراخوانی نمودیم. خروجی این تابع که خود یک تابع با یک آرگومان ورودی می‌باشد، به عنوان خروجی برگردانده شده و در متغیر fn قرار می‌گیرد. سپس تابع fn با آرگومان ورودی 30 فراخوانی می‌گردد که مقادیر 10 و 20 را با هم جمع نموده و در 30 ضرب می‌نماید. 

نظرات مطالب
نمایش فرم‌های مودال Ajax ایی در ASP.NET MVC به کمک Twitter Bootstrap
با سلام
منظورتون رو از مطلب زیر نفهمیدم. میشه بگید چطوری میتونیم با استفاده از alert خود بوت استرپ نتیجه را از کنترلر به فرم مدال ارسال کنیم و در آنجا نمایش دهیم؟
«این مورد پیش بینی شده در این مثال. اگر به خروجی اکشن متد دقت کنید، چنین چیزی است:
1
return Json( new { success = true });
همین مورد یعنی بررسی مقدار success دریافتی، جایی که عملیات Ajax ایی ارسال اطلاعات پایان می‌یابد انجام شده:
1
2
3
4
if (result.success) {
  $( '#dialogDiv' ).modal( 'hide' );
  if (options.completeHandler)
options.completeHandler();
بنابراین تنها کاری که باید انجام بدید، قرار دادن کدهای نمایش اطلاعات نهایی در callbackهای completeHandler  ویا  errorHandler   مربوط به افزونه  $.bootstrapModalAjaxForm   است. اینجا دست شما باز است. اگر علاقمند بودید از یک alert ساده استفاده کنید» 
مطالب
جایگزین کردن jQuery با JavaScript خالص - قسمت پنجم - درخواست‌های Ajax
AJAX و یا «Asynchronous JavaScript and XML» قابلیتی است که توسط web API جاوا اسکریپتی مرورگرها برای دریافت و یا به روز رسانی اطلاعات، بدون بارگذاری مجدد و کامل صفحه، ارائه می‌شود. این قابلیت اولین بار در سال 1999 توسط مایکروسافت با ارائه‌ی مرورگر IE 5.0 و معرفی شیء XMLHTTP که توسط یک ActiveX control ارائه می‌شد، میسر گردید و این روزها توسط استاندارد XMLHttpRequest در تمام مرورگرها قابل استفاده است. این استاندارد نیز مدتی است که توسط Fetch API مرورگرهای جدید جایگزین شده‌است (پس از 15 سال از ارائه‌ی استاندارد XMLHttpRequest) و در این لحظه در تمام مرورگرهای غالب وب پشتیبانی می‌شود.
در ادامه روش‌های مختلف ارسال درخواست‌های Ajax را توسط jQuery و همچنین معادل‌های XMLHttpRequest و Fetch API آن‌ها بررسی می‌کنیم.


ارسال درخواست‌های GET

توسط استاندارد جدید Fetch API 
  توسط XMLHttpRequest استاندارد  توسط jQuery 
 fetch('/my/name').then(function(response) {
  if (response.ok) {
   return response.text();
  }
  else {
   throw new Error();
  }
 }).then(
  function success(name) {
  console.log('my name is ' + name);
  },
  function failure() {
  console.error('Name request failed!');
  }
 );
 var xhr = new XMLHttpRequest();
  xhr.open('GET', '/my/name');
 xhr.onload = function() {
  if (xhr.status >= 400) {
   console.error('Name request failed!');
  }
  else {
   console.log('my name is ' + xhr.responseText);
  }
 };
 xhr.onerror = function() {
  console.error('Name request failed!');
 };
 xhr.send();
 $.get('/my/name').then(
  function success(name) {
  console.log('my name is ' + name);
  },
  function failure() {
  console.error('Name request failed!');
  }
 );

jQuery برای پشتیبانی از درخواست‌های Ajax، متد ویژه‌ای را به نام ()ajax ارائه می‌کند که برای ارسال درخواست‌هایی از هر نوع، مانندGET، POST و غیره کاربرد دارد. همچنین برای بعضی از نوع‌ها، متدهای کوتاه‌تری را مانند ()get و ()post نیز در اختیار برنامه نویس قرار می‌دهد. جاوا اسکریپت خالص و Web API مرورگرها نیز دو شیء XMLHttpRequest و fetch را برای ارسال درخواست‌های غیرهمزمان، ارائه می‌کند. XMLHttpRequest در تمام مرورگرهای قدیمی و جدید پشتیبانی می‌شود، اما fetch API مدتی است که در غالب مرورگرهای امروزی در دسترس است. در جدول فوق روش ارسال درخواست‌های Ajax از نوع GET را توسط این سه روش مشاهده می‌کنید.
در این مثال‌ها درخواستی به آدرس my/name سمت سرور ارسال شده و انتظار می‌رود که یک plaintext حاوی متن کاربر بازگشت داده شود که در نهایت در console لاگ می‌شود.
- در حالت استفاده‌ی از jQuery در صورت بازگشت موفقیت آمیز پاسخی از طرف سرور، متد success و در غیراینصورت متد failure اجرا می‌شود. باید درنظر داشت که متد ajax جی‌کوئری، چیزی بیشتر از یک محصور کننده‌ی اشیاء XMLHttpRequest نیست.
- در حالت کار با XMLHttpRequest باید اندکی بیشتر تایپ کرد؛ اما اصول کار یکی است. در اینجا onload زمانی فراخوانی می‌شود که پاسخی از سرور دریافت شده و عملیات خاتمه یافته‌است؛ هرچند این پاسخ می‌تواند یک خطا نیز باشد. به همین جهت باید status آن‌را بررسی کرد. اگر رخ‌داد onerror فراخوانی شد، یعنی درخواست، در سطوح بسیار پایین آن مانند بروز یک خطای CORS با شکست مواجه شده‌است.
همانطور که مشاهده می‌کنید در حالت کار با XMLHttpRequest جاوا اسکریپت از اشیاء Promise پشتیبانی نمی‌کند که این کمبود با معرفی fetch API برطرف شده‌است که نمونه‌ای از آن‌را با متد then متصل به fetch مشاهده می‌کنید؛ دقیقا مشابه متد ajax جی‌کوئری که آن نیز یک Promise را بازگشت می‌دهد.
تفاوت Promise جی‌کوئری با fetch API در این است که جی‌کوئری در صورتیکه یک status code بیانگر خطا را دریافت کند، قسمت failure را اجرا می‌کند؛ اما fetch API مانند اشیاء XMLHttpRequest تنها در صورت بروز خطاهای سطح پایین درخواست، این متد را فراخوانی خواهد کرد. هرچند اگر در اینجا response.ok نبود، می‌توان با صدور یک استثناء به رفتاری شبیه به jQuery رسید و قسمت then failure را به صورت خودکار اجرا کرد.


ارسال درخواست‌های Ajax از نوع POST ، PUT و DELETE

در اینجا اطلاعاتی با MIME type از نوع plaintext به سمت سرور ارسال می‌شود. جهت سهولت توضیح و تمرکز بر روی قسمت‌های مهم آن، بخش مدیریت پاسخ آن حذف شده‌است و این مورد دقیقا با مثال قبلی که در مورد درخواست‌های از نوع GET بود، یکی است.
توسط استاندارد جدید Fetch API 
توسط XMLHttpRequest استاندارد 
توسط jQuery 
 fetch('/user/name', {
  method: 'POST',
  body: 'some data'
 });
 var xhr = new XMLHttpRequest();
 xhr.open('POST', '/user/name');
 xhr.send('some data');
 $.ajax({
  method: 'POST',
  url: '/user/name',
  contentType: 'text/plain',
  data: 'some data'
 });
در حالت ارسال اطلاعات به سرور با متد POST، نیاز است contentType متد ajax جی‌کوئری حتما ذکر شود. در غیراینصورت آن‌را به application/x-www-form-urlencoded تنظیم می‌کند که ممکن است الزاما مقداری نباشد که مدنظر ما است. در اینجا بدنه‌ی درخواست به خاصیت data انتساب داده می‌شود.
اگر از شیء XMLHttpRequest استفاده شود، Content-Type آن به صورت پیش‌فرض به text/plain تنظیم شده‌است. در اینجا بدنه‌ی درخواست به متد send ارسال می‌شود.
متد fetch نیز همانند شیء XMLHttpRequest دارای Content-Type پیش‌فرض از نوع text/plain است. در اینجا بدنه‌ی درخواست به خاصیت body انتساب داده می‌شود.

درخواست‌های از نوع POST عموما برای ایجاد رکوردی جدید در سمت سرور مورد استفاده قرار می‌گیرند و از درخواست‌های PUT بیشتر برای به روز رسانی مقادیر موجود یک رکورد کمک گرفته می‌شود. درخواست‌های از نوع PUT نیز دقیقا مانند درخواست‌های از نوع POST در اینجا مدیریت می‌شوند و در هر سه حالت، متد ارسال اطلاعات، به مقدار PUT تنظیم خواهد شد:
توسط استاندارد جدید Fetch API 
توسط XMLHttpRequest استاندارد 
 توسط jQuery 
 fetch('/user/1', {
  method: 'PUT',
  body: //record including new mobile number 
 });
 var xhr = new XMLHttpRequest();
 xhr.open('PUT', '/user/1');
 xhr.send(/* record including new data */);
 $.ajax({
  method: 'PUT',
  url: '/user/1',
  contentType: 'text/plain',
  data: //record including new data
 });
درخواست‌های از نوع DELETE نیز مانند قبل بوده و تنها تفاوت آن، نداشتن بدنه‌ی درخواست است:
 توسط استاندارد جدید Fetch API   توسط XMLHttpRequest استاندارد  توسط jQuery 
 fetch('/user/1', {method: 'DELETE'});
 var xhr = new XMLHttpRequest();
 xhr.open('DELETE', '/user/1');
 xhr.send();
 $.ajax('/user/1', {method: 'DELETE'});


مدیریت Encoding درخواست‌های Ajax

در مثال‌های قبل، اطلاعاتی از نوع text/plain را به سمت سرور ارسال کردیم که به آن encoding type نیز گفته می‌شود. برای تکمیل بحث می‌توان حالت‌های دیگری مانند application/x-www-form-urlencoded، application/json و یا multipart/form-data را که در برنامه‌های کاربردی زیاد مورد استفاده قرار می‌گیرند، بررسی کرد.

کار با URL Encoding

عموما URL encoding در دو قسمت آدرس درخواستی به سرور و یا حتی بدنه‌ی درخواست ارسالی تنظیم می‌شود. MIME type آن نیز application/x-www-form-urlencoded است و اطلاعات آن شامل یکسری جفت کلید/مقدار است. برای متدهای ارسال از نوع GET و DELETE، اطلاعات آن در انتهای آدرس درخواستی و برای سایر حالات در بدنه‌ی درخواست ذکر می‌شوند.
در جی‌کوئری با استفاده از متد param آن می‌توان یک شیء جاوا اسکریپتی را به معادل URL-encoded string آن‌ها تبدیل کرد:
$.param({
  key1: 'some value',
  'key 2': 'another value'
});
با این خروجی encode شده:
 key1=some+value&key+2=another+value
البته باید دقت داشت زمانیکه از متد ajax جی‌کوئری استفاده می‌شود، دیگر نیازی به استفاده‌ی مستقیم از متد param نیست:
 $.ajax({
  method: 'POST',
  url: '/user',
  data: {
  name: 'VahidN',
  address: 'Address 1',
  phone: '555-555-5555'
  }
 });
در اینجا یک شیء جاوا اسکریپتی معمولی به خاصیت data آن نسبت داده شده‌است که در پشت صحنه در حین ارسال به سرور، چون Content-Type پیش‌فرض (و ذکر نشده‌ی در اینجا) دقیقا همان application/x-www-form-urlencoded است، به صورت خودکار تبدیل به یک URL-encoded string می‌شود.

برخلاف جی‌کوئری در حین کار با روش‌های جاوا اسکریپتی خالص این encoding باید به صورت دستی و صریحی انجام شود. برای این منظور دو متد استاندارد encodeURI و encodeURIComponent در جاوا اسکریپت مورد استفاده قرار می‌گیرند. هدف متد encodeURI اعمال آن بر روی یک URL کامل است و یا کلید/مقدارهای جدا شده‌ی توسط & مانند first=Vahid&last=N. اما متد encodeURIComponent صرفا جهت اعمال بر روی یک تک مقدار طراحی شده‌است.
به این ترتیب معادل جاوا اسکریپتی قطعه کد جی‌کوئری فوق به صورت زیر است:
 var xhr = new XMLHttpRequest();
 var data = encodeURI('name=VahidN&address=Address 1&phone=555-555-5555');
 xhr.open('POST', '/user');
 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 xhr.send(data);
که در آن data توسط encodeURI تبدیل به یک رشته‌ی URL-encoded شده و سپس با ذکر صریح Content-Type به سمت سرور ارسال می‌شود.
روش انجام اینکار توسط fetch API به صورت زیر است:
   var data = encodeURI('name=VahidN&address=Address 1&phone=555-555-5555');
  fetch('/user', {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: data
 });
معادل متد param جی‌کوئری با جاوا اسکریپت خالص به صورت زیر است؛ برای تبدیل یک شیء جاوا اسکریپتی به معادل URL-encoded string آن:
function param(object) {
    var encodedString = '';
    for (var prop in object) {
        if (object.hasOwnProperty(prop)) {
            if (encodedString.length > 0) {
                encodedString += '&';
            }
            encodedString += encodeURI(prop + '=' + object[prop]);
        }
    }
    return encodedString;
}


کار با JSON Encoding

در عمل JSON نمایش رشته‌ای یک شیء جاوا اسکریپتی است و هدف آن سهولت نقل و انتقالات این اشیاء به سرور و برعکس است. برخلاف حالت application/x-www-form-urlencoded که اطلاعات آن مسطح است، حالت application/json امکان ارسال اطلاعات سلسله مراتبی را نیز میسر می‌کند (مانند مثال زیر که phone آن دیگر مسطح نیست و خود آن نیز یک شیء جاوا اسکریپتی است).
 در جی‌کوئری برای ارسال اشیاء جاوا اسکریپتی JSON Encoded به سمت سرور از روش زیر استفاده می‌شود:
 $.ajax({
  method: 'POST',
  url: '/user',
  contentType: 'application/json',
  data: JSON.stringify({
   name: 'VahidN',
   address: 'Address 1',
   phone: {
   home: '555-555-5555',
   mobile: '444-444-4444'
  }
  });
 });
در اینجا نسبت به مثال قبلی، ذکر Content-Type ضروری بوده و همچنین data نیز باید به صورت دستی encode شود. برای این منظور می‌توان از متد استاندارد JSON.stringify استفاده کرد که از زمان IE 8.0 به بعد در تمام مرورگرها پشتیبانی می‌شود.
پیاده سازی همین مثال با جاوا اسکریپت خالص و XMLHttpRequest استاندارد به صورت زیر است:
  var xhr = new XMLHttpRequest();
 var data = JSON.stringify({
   name: 'VahidN',
   address: 'Address 1',
   phone: {
    home: '555-555-5555',
    mobile: '444-444-4444'
   }
   });
 xhr.open('POST', '/user');
 xhr.setRequestHeader('Content-Type', 'application/json');
 xhr.send(data);
که در اینجا نیز Content-Type به صورت صریحی ذکر و از متد JSON.stringify برای encode دستی اطلاعات کمک گرفته شده‌است.
در این حالت اگر خروجی سرور نیز JSON باشد، روش دریافت و پردازش آن به صورت زیر است:
 var xhr = new XMLHttpRequest();
 xhr.open('GET', '/user/1');
 xhr.onload = function() {
  var user = JSON.parse(xhr.responseText);
  // do something with this user JavaScript object 
 };
 xhr.send();
رخ‌داد onload، پس از پایان درخواست فراخوانی می‌شود. در اینجا برای دسترسی به response body می‌توان از خاصیت responseText استفاده کرد و سپس توسط متد JSON.parse این رشته را تبدیل به یک شیء جاوا اسکریپتی نمود.
اگر از مرورگر IE صرفنظر کنیم، تمام مرورگرهای دیگر دارای خاصیتی به نام xhr.response نیز هستند که نیاز به تبدیل و Parse دستی رشته‌ی دریافتی را حذف می‌کند؛ از این جهت که این خاصیت حاوی شیء جاوا اسکریپتی معادل بدنه‌ی response دریافتی از سمت سرور است. البته با این شرط که سرور، Content-Type مساوی application/json را برای response تنظیم کرده باشد.
و روش انجام این عملیات توسط fetch API به صورت زیر است:
 fetch('/user', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
   name: 'VahidN',
   address: 'Address 1',
   phone: {
   home: '555-555-5555',
   mobile: '444-444-4444'
  }
  });
 });
که در اینجا نیز هدر Content-Type تنظیم و همچنین از متد JSON.stringify برای تبدیل شیء جاوا اسکریپتی به رشته‌ی معادل، استفاده شده‌است.
و یا اگر بخواهیم اطلاعات JSON دریافتی از سمت سرور را در اینجا پردازش کنیم، روش کار به صورت زیر است:
 fetch('/user/1').then(function(response) {
  return response.json();
  }).then(function(userRecord) {
   // do something with this user JavaScript object 
 });
Fetch API به صورت یک Promise، امکان دسترسی به شیء response را مهیا می‌کند. چون می‌دانیم خروجی آن json است، از متد ()json آن که یک Promise را بازگشت می‌دهد استفاده خواهیم کرد. پس از پایان موفقیت آمیز درخواست، then دوم تعریف شده، اجرا و userRecord ارسالی به آن، همان شیء جاوا اسکریپتی دریافتی از سمت سرور است.
همین مثال را اگر بخواهیم توسط ECMAScript 2016 و Arrow functions آن بازنویسی کنیم، به قطعه کد زیر می‌رسیم:
 fetch('/user/1')
  .then(response => response.json()) // Transform the data into json 
  .then(userRecord => {
  // do something with this userRecord object
  });


کار با Multipart Encoding

نوع دیگری از encoding که بیشتر با فرم‌های HTML بکار می‌رود، multipart/form-data نام دارد:
 <form action="my/server" method="POST" enctype="multipart/form-data">
  <label>First Name:
   <input name="first">
  </label>
 
  <label>Last Name:
   <input name="last">
  </label>
 
  <button>Submit</button>
 </form>
با فعال بودن این نوع encoding، اطلاعات نمونه‌ی فرم فوق به شکل زیر به سمت سرور ارسال می‌شوند:
 -----------------------------1686536745986416462127721994
 Content-Disposition: form-data; name="first"

 Vahid
 -----------------------------1686536745986416462127721994
 Content-Disposition: form-data; name="last"

 N
 -----------------------------1686536745986416462127721994--
از این روش نه فقط برای ارسال اطلاعات کلید/مقدارها و اشیاء جاوا اسکریپتی استفاده می‌شود، بلکه از آن برای ارسال اطلاعات فایل‌های باینری نیز کمک گرفته می‌شود.
روش ارسال اطلاعات با این نوع encoding خاص به سمت سرور توسط متد ajax جی‌کوئری به صورت زیر است:
  var formData = new FormData();
 formData.append('name', 'VahidN');
 formData.append('address', 'Address 1');
 formData.append('phone', '555-555-5555');
 
 $.ajax({
  method: 'POST',
  url: '/user',
  contentType: false,
  processData: false,
  data: formData
 });
همانطور که ملاحظه می‌کنید jQuery روش توکاری را برای انجام اینکار نداشته و باید از FormData جاوا اسکریپت یا همان web API مرورگرها به همراه متد ajax آن استفاده کرد. در این حالت اطلاعات به صورت کلید/مقدارها به شیء استاندارد FormData اضافه شده و سپس به سمت سرور ارسال می‌شوند. باید دقت داشت FormData از نگارش‌های پس از IE 9.0 در دسترس است.
در اینجا ذکر processData: false ضروری است. در غیراینصورت jQuery این اطلاعات را به یک URL-encoded string تبدیل می‌کند. همچنین با اعلام contentType: false، جی‌کوئری در کار مرورگر دخالت نمی‌کند. از این جهت که هدر ویژه‌ی این نوع درخواست‌ها توسط خود مرورگر تنظیم می‌شود و برای مثال یک چنین شکلی را دارد:
 multipart/form-data; boundary=—————————1686536745986416462127721994
این عدد انتهای هدر یک unique ID است که جزئی از اطلاعات multipart بوده و توسط مرورگر به انتهای هدر اصلی multipart/form-data اضافه می‌شود.

روش انجام اینکار با XMLHttpRequest و همچنین fetch API به صورت زیر است:
توسط استاندارد جدید Fetch API 
توسط XMLHttpRequest استاندارد 
 var formData = new FormData();
 formData.append('name', 'VahidN');
 formData.append('address', 'Address 1');
 formData.append('phone', '555-555-5555');

 fetch('/user', {
  method: 'POST',
  body: formData
 });
 var formData = new FormData(),
  xhr = new XMLHttpRequest();

 formData.append('name', 'VahidN');
 formData.append('address', 'Address 1');
 formData.append('phone', '555-555-5555');

 xhr.open('POST', '/user');
 xhr.send(formData);
همانطور که مشاهده می‌کنید قسمت استفاده‌ی از FormData استاندارد در اینجا یکسان است و همچنین نیازی به ذکر هدر و یا اطلاعات اضافه‌تری نیست.


آپلود فایل‌ها توسط درخواست‌های Ajax ایی

تنها راه آپلود فایل‌ها در مرورگرهای قدیمی که شامل IE 9.0 هم می‌شود، تعریف المان <"input type="file> در داخل المان <form> و سپس submit مستقیم آن فرم است. برای رفع این مشکل در مرورگرهای پس از IE 9.0 و پشتیبانی از Ajax، جهت آپلود فایل‌ها، استاندارد XMLHttpRequest Level 2 معرفی شده‌است. در این حالت اگر المان <input type=file> در صفحه وجود داشته باشد، روش ارسال Ajax ایی آن به سمت سرور به صورت زیر است:
توسط استاندارد جدید Fetch API 
 توسط XMLHttpRequest استاندارد  توسط jQuery 
var file = document.querySelector(
      'INPUT[type="file"]').files[0];
fetch('/uploads', {
  method: 'POST',
  body: file
  });
 }
var file = document.querySelector(
    'INPUT[type="file"]').files[0],
xhr = new XMLHttpRequest();
xhr.open('POST', '/uploads');
xhr.send(file);

var file = $('INPUT[type="file"]')[0].files[0]; 
$.ajax({
   method: 'POST',
   url: '/uploads',
   contentType: false,
   processData: false,
   data: file
  });
در اینجا روش آپلود یک تک فایل را به سرور، توسط درخواست‌های Ajax ایی مشاهده می‌کنید و توضیحات contentType: false و processData: false آن مانند قبل است تا jQuery این اطلاعات multipart را پیش از ارسال به سرور دستکاری نکند.
یک نکته: اگر نیاز به آپلود بیش از یک فایل را داشتید و همچنین در اینجا نیاز به اطلاعات دیگری مانند سایر فیلدهای فرم نیز وجود داشت، از همان روش تعریف  new FormData و افزودن اطلاعات مورد نیاز به آن استفاده کنید. امکان افزودن شیء file نیز به FormData پیش بینی شده‌است.


دانلود فایل‌ها توسط درخواست‌های Ajax ایی

پیشتر در حین بررسی JSON encoding توسط fetch API از متد ()json برای تبدیل اطلاعات دریافتی از سرور به json و بازگشت آن به صورت یک Promise استفاده کردیم:
  fetch(url) 
  .then((resp) => resp.json()) // Transform the data into json 
  .then(function(data) { 
    // use data object
    }) 
  })
در اینجا علاوه بر ()json، متدهای استاندارد دیگری نیز پیش بینی شده‌اند که همگی یک Promise را بازگشت می‌دهند:
- ()clone یک کپی از response را تهیه می‌کند.
- ()redirect یک response جدید را با URL دیگری ایجاد می‌کند.
- ()arrayBuffer یک Promise را بازگشت می‌دهد که پس از پایان درخواست، response را به یک شیء ArrayBuffer تبدیل می‌کند.
- ()formData یک Promise را بازگشت می‌دهد که پس از پایان درخواست، response را به یک شیء FormData تبدیل می‌کند.
- ()blob یک Promise را بازگشت می‌دهد که پس از پایان درخواست، response را به یک شیء Blob تبدیل می‌کند.
- ()text یک Promise را بازگشت می‌دهد که پس از پایان درخواست، response را به string تبدیل می‌کند.
- ()json یک Promise را بازگشت می‌دهد که پس از پایان درخواست، response را به یک شیء جاوا اسکریپتی تبدیل می‌کند.

در اینجا متدی که می‌تواند برای تبدیل یک byte array بازگشتی از سرور به فایل قابل دریافت در سمت کلاینت مورد استفاده قرار گیرد، متد blob است:
function downloadBlob()
{
       fetch('/Home/InMemoryReport')
   .then(function(response) {
         return response.blob();
   })
   .then(function(xlsxBlob) {
             var a = document.createElement("a");
             document.body.appendChild(a);
             a.style = "display: none";
             let url = window.URL.createObjectURL(xlsxBlob);
             a.href = url;
             a.download = "report.xlsx";
             a.click();
             window.URL.revokeObjectURL(url);
   });
}
فرض کنید مسیر Home/InMemoryReport یک گزارش PDF و یا اکسل را به صورت byte array بازگشت می‌دهد. اولین then نوشته شده، درخواست تبدیل این byte array را پس از پایان response به یک شیء Blob می‌دهد. پس از پایان درخواست، این Promise اجرا شده و نتیجه‌ی آن به صورت خودکار در اختیار then دوم قرار می‌گیرد. در اینجا همانطور که در قسمت قبل نیز بررسی کردیم، یک المان جدید anchor مخفی را ایجاد کرده و به صفحه اضافه می‌کنیم. سپس url آن‌را به این شیء Blob، توسط متد استاندارد window.URL.createObjectURL تنظیم می‌کنیم. با استفاده از متد URL.createObjectURL می‌توان آدرس موقت محلی را برای دسترسی به آن تولید کرد و یک چنین آدرس‌هایی به صورت blob:http تولید می‌شوند. نام این فایل را هم توسط ویژگی download این شیء می‌توان تنظیم نمود. در نهایت بر روی آن، متد click را فراخوانی می‌کنیم. با اینکار مرورگر این فایل را به صورت یک فایل دریافت شده‌ی متداول در لیست فایل‌های آن قرار می‌دهد. این روش در مورد تدارک دکمه‌ی دریافت تمام blobهای دریافتی از سرور کاربرد دارد.


ارسال درخواست‌های Ajax به دومین‌های دیگر (CORS)

گاهی از اوقات نیاز است اطلاعاتی را توسط درخواست‌های Ajax، به سروری دیگر در دومینی دیگر ارسال و یا دریافت کرد. هرچند انجام اینکار به صورت مستقیم و خارج از مرورگر بدون مشکل قابل انجام است، اما مرورگرها برای درخواست‌های جاوا اسکریپتی محدودیت «same-origin policy» را اعمال می‌کنند. به این معنا که XMLHttpRequest بین دومین‌ها به صورت پیش‌فرض ممنوع است. برای ارسال درخواست‌های مجاز و از پیش مشخص شده‌ی Ajax بین دومین‌ها، تاکنون دو روش پیش بینی شده‌است:
الف) روش JSONP
«same-origin policy» از شروع ارسال درخواستی به خارج از دومین جاری، جلوگیری می‌کند. هرچند این مورد به درخواست‌های XMLHttpRequest اعمال می‌شود، اما در مورد المان‌هایی از نوع <a>، <img>  و  <script> صادق نیست و آن‌ها محدود به این سیاست امنیتی نیستند. روش «JavaScript Object Notation with Padding» و یا به اختصار JSONP از یکی از همین استثناءها جهت ارسال درخواست‌هایی به سایر دومین‌ها استفاده می‌کند. البته نام این روش کمی غلط انداز است؛ از این جهت که در این فرآیند اصلا JSON ایی مورد استفاده قرار نمی‌گیرد؛ خروجی سرور در این حالت یک تابع جاوا اسکریپتی است و نه JSON.
روش انجام این نوع درخواست‌ها را توسط جی‌کوئری در ذیل مشاهده می‌کنید:
 $.ajax('http://jsonp-aware-endpoint.com/user/1', {
  jsonp: 'callback',
  dataType: 'jsonp'
 }).then(function(response) {
  // handle user info from server 
 });
در این حالت jQuery پس از اجرای تابع دریافتی از سرور، نتیجه‌ی آن‌را در قسمت then، در اختیار مصرف کننده قرار می‌دهد.
انجام اینکار بدون jQuery و در حقیقت کاری که jQuery در پشت صحنه برای ایجاد تگ script انجام می‌دهد، چنین چیزی است:
 window.myJsonpCallback = function(data) {
  // handle user info from server 
 };

 var scriptEl = document.createElement('script');
 scriptEl.setAttribute('src',
  'http://jsonp-aware-endpoint.com/user/1?callback=myJsonpCallback');
 document.body.appendChild(scriptEl);
هرچند این روش هنوز هم در بعضی از سایت‌ها مورد استفاده‌است، در کل بهتر است از آن دوری کنید؛ چون ممکن است به مشکلات امنیتی دیگری ختم شود. این روش بیشتر در روزهای آغازین معرفی محدودیت «same-origin policy» بکار گرفته می‌شد (در زمان IE 7.0).


ب) روش CORS

CORS  و یا Cross Origin Resource Sharing روش مدرن و پذیرفته شده‌ی ارسال درخواست‌های Ajax در بین دومین‌ها است و دارای دو نوع ساده و غیرساده است. نوع ساده‌ی آن به همراه هدر مخصوص Origin است که جهت بیان دومین ارسال کننده‌ی درخواست بکار می‌رود و تنها از encodingهای “text/plain”  و  “application/x-www-form-urlencoded”  پشتیبانی می‌کند. نوع غیرساده‌ی آن که این روزها بیشتر بکار می‌رود، از نوع «preflight» است. Preflight در اینجا به این معنا است که زمانیکه درخواست Ajax ایی را به دومین دیگری ارسال کردید، پیش از ارسال، مرورگر یک درخواست از نوع OPTIONS را به سمت سرور مقصد ارسال می‌کند. در این حالت اگر سرور مجوز مناسبی را صادر کرد، آنگاه مرورگر اصل درخواست را به سمت آن سرور ارسال می‌کند. به همین جهت در این حالت به ازای هر درخواستی که در برنامه ارسال می‌شود، در برگه‌ی network مرورگر، دو درخواست را مشاهده خواهید کرد. درخواست preflight از نوع OPTIONS به صورت خودکار توسط مرورگر مدیریت می‌شود و نیازی به کدنویسی خاصی ندارد.


مدیریت کوکی‌ها در درخواست‌های Ajax

اگر درخواست Ajax ایی را به دومین دیگری ارسال کنید، به صورت پیش‌فرض به همراه کوکی‌های مرتبط نخواهد بود. برای رفع این مشکل نیاز است خاصیت withCredentials را به true تنظیم کنید:
توسط استاندارد جدید Fetch API 
توسط XMLHttpRequest استاندارد 
 توسط jQuery 
 fetch('http://someotherdomain.com', {
  method: 'POST',
  headers: {
  'Content-Type': 'text/plain'
  },
  credentials: 'include'
 });
 var xhr = new XMLHttpRequest();
 xhr.open('POST', 'http://someotherdomain.com');
 xhr.withCredentials = true;
 xhr.setRequestHeader('Content-Type', 'text/plain');
 xhr.send('sometext');
 $.ajax('http://someotherdomain.com', {
  method: 'POST',
  contentType: 'text/plain',
  data: 'sometext',
  beforeSend: function(xmlHttpRequest) {
  xmlHttpRequest.withCredentials = true;
  }
 });
 
یک نکته‌ی مهم: در fetch API حتی برای درخواست‌های ساده نیز کوکی‌ها ارسال نمی‌شوند. در این حالت برای کار با دومین جاری و ارسال کوکی‌های کاربر به سمت سرور، باید از تنظیم 'credentials: 'same-origin استفاده کرد؛ زیرا مقدار پیش‌فرض آن omit است.
مطالب
یافتن آدرس نهایی یک Url پس از Redirect

برای مثال آدرس http://feedproxy.google.com/~r/nettuts/~3/tWCksueANyY/ را در نظر بگیرید. گوگل پس از خرید feedburner ، از feedproxy.google.com جهت ردیابی آدرس‌های فیدها استفاده می‌کند؛‌ مثلا فید شما چند نفر خواننده دارد، کدام موارد بیشتر خوانده شده، با چه مرورگرهایی، از چه مکان‌هایی و مواردی از این دست. البته می‌توان در تنظیمات فیدبرنر این نوع آدرس دهی را خاموش کرد ولی به صورت پیش فرض فعال است. مشکل feedproxy.google.com هم این است که در ایران فیلتر است. بنابراین یافتن آدرس اصلی این نوع لینک‌ها پس از Redirect نهایی می‌تواند جهت ارائه عمومی آن‌ها مفید باشد. با استفاده از قطعه کد زیر می‌توان این آدرس را یافت:

using System;
using System.Net;

namespace Linq2Rss
{
public class RedirectFinder
{
public CookieContainer Cookies { set; get; }
public string Url { get; set; }

public string GetRedirectUrl()
{
var hops = 1;
const int MaxRedirects = 20;

do
{
var request = (HttpWebRequest)WebRequest.Create(Url);
request.UserAgent = "MyUA";
request.KeepAlive = true;
request.Referer = Url;
if (Cookies == null) Cookies = new CookieContainer();
request.CookieContainer = Cookies;
request.AllowAutoRedirect = false;

using (var webResp = request.GetResponse() as HttpWebResponse)
{
if ((webResp.StatusCode == HttpStatusCode.Found) ||
(webResp.StatusCode == HttpStatusCode.Redirect) ||
(webResp.StatusCode == HttpStatusCode.Moved) ||
(webResp.StatusCode == HttpStatusCode.MovedPermanently))
{
var newLocation = webResp.Headers["Location"];
if (newLocation.StartsWith("/"))
{
var uri = new Uri(Url);
Url = string.Format("{0}://{1}:{2}{3}", uri.Scheme, uri.Host, uri.Port, newLocation);
}
else
Url = newLocation;
}
else
{
if (webResp.StatusCode == HttpStatusCode.OK)
return Url;
}
}

hops++;
} while (hops <= MaxRedirects);
return Url;
}
}
}


برای یافتن آدرس واقعی یک Url پس از Redirect راهی بجز درخواست آن از وب سرور اولیه وجود ندارد. سپس وضعیت پاسخ داده شده بررسی می‌شود؛ اگر حاوی Found ، Moved یا Redirect بود، به این معنا است که باید آدرس جدید را از هدر پاسخ دریافتی استخراج کنیم. این آدرس، در کلید Location ذخیره می‌شود. اکنون یکبار دیگر نیاز است تا این آدرس جدید بررسی شود، زیرا ممکن است این مورد هم به آدرس دیگری اشاره کند. در کل، کد فوق 20 بار این بررسی را انجام خواهد داد (هر چند عموما در دو یا سه سعی به جواب خواهیم رسید).
مطالب
استفاده از Kendo UI templates
در مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» در انتهای بحث، ستون IsAvailable به صورت زیر تعریف شد:
columns: [
               {
                   field: "IsAvailable", title: "موجود است",
                   template: '<input type="checkbox" #= IsAvailable ? checked="checked" : "" # disabled="disabled" ></input>'
                }
]
Templates، جزو یکی از پایه‌های Kendo UI Framework هستند و توسط آن‌ها می‌توان قطعات با استفاده‌ی مجدد HTML ایی را طراحی کرد که قابلیت یکی شدن با اطلاعات جاوا اسکریپتی را دارند.
همانطور که در این مثال نیز مشاهده می‌کنید، قالب‌های Kendo UI از Hash (#) syntax استفاده می‌کنند. در اینجا قسمت‌هایی از قالب که با علامت # محصور می‌شوند، در حین اجرا، با اطلاعات فراهم شده جایگزین خواهند شد.
برای رندر مقادیر ساده می‌توان از # =# استفاده کرد. از # :# برای رندر اطلاعات HTML-encoded کمک گرفته می‌شود و #  # برای رندر کدهای جاوا اسکریپتی کاربرد دارد. از حالت HTML-encoded برای نمایش امن اطلاعات دریافتی از کاربران و جلوگیری از حملات XSS استفاده می‌شود.
اگر در این بین نیاز است # به صورت معمولی رندر شود، در حالت کدهای جاوا اسکریپتی به صورت #\\ و در HTML ساده به صورت #\ باید مشخص گردد.


مثالی از نحوه‌ی تعریف یک قالب Kendo UI

    <!--دریافت اطلاعات از منبع محلی-->
    <script id="javascriptTemplate" type="text/x-kendo-template">
        <ul>
            # for (var i = 0; i < data.length; i++) { #
            <li>#= data[i] #</li>
            # } #
        </ul>
    </script>

    <div id="container1"></div>
    <script type="text/javascript">
        $(function () {
            var data = ['User 1', 'User 2', 'User 3'];
            var template = kendo.template($("#javascriptTemplate").html());
            var result = template(data); //Execute the template
            $("#container1").html(result); //Append the result
        });
    </script>
این قالب ابتدا در تگ script محصور می‌شود و سپس نوع آن مساوی text/x-kendo-template قرار می‌گیرد. در ادامه توسط یک حلقه‌ی جاوا اسکریپتی، عناصر آرایه‌ی فرضی data خوانده شده و با کمک Hash syntax در محل‌های مشخص شده قرار می‌گیرند.
در ادامه باید این قالب را رندر کرد. برای این منظور یک div با id مساوی container1 را جهت تعیین محل رندر نهایی اطلاعات مشخص می‌کنیم. سپس متد kendo.template بر اساس id قالب اسکریپتی تعریف شده، یک شیء قالب را تهیه کرده و سپس با ارسال آرایه‌ای به آن، سبب اجرای آن می‌شود. خروجی نهایی، یک قطعه کد HTML است که در محل container1 درج خواهد شد.
همانطور که ملاحظه می‌کنید، متد kendo.template، نهایتا یک رشته را دریافت می‌کند. بنابراین همینجا و به صورت inline نیز می‌توان یک قالب را تعریف کرد.


کار با منابع داده راه دور

فرض کنید مدل برنامه به صورت ذیل تعریف شده‌است:
namespace KendoUI04.Models
{
    public class Product
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public decimal Price { set; get; }
        public bool IsAvailable { set; get; }
    }
}
و لیستی از آن توسط یک ASP.NET Web API کنترلر، به سمت کاربر ارسال می‌شود:
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using KendoUI04.Models;

namespace KendoUI04.Controllers
{
    public class ProductsController : ApiController
    {
        public IEnumerable<Product> Get()
        {
            return ProductDataSource.LatestProducts.Take(10);
        }
    }
}
در سمت کاربر و در View برنامه خواهیم داشت:
    <!--دریافت اطلاعات از سرور-->
    <div>
        <div id="container2"><ul></ul></div>
    </div>

    <script id="template1" type="text/x-kendo-template">
        <li> #=Id# - #:Name# - #=kendo.toString(Price, "c")#</li>
    </script>

    <script type="text/javascript">
        $(function () {
            var producatsTemplate1 = kendo.template($("#template1").html());

            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);
                },
                change: function () {
                    $("#container2 > ul").html(kendo.render(producatsTemplate1, this.view()));
                }
            });
            productsDataSource.read();
        });
    </script>
ابتدا یک div با id مساوی container2 جهت تعیین محل نهایی رندر قالب template1 در صفحه تعریف می‌شود.
هرچند خروجی دریافتی از سرور نهایتا یک آرایه از اشیاء Product است، اما در template1 اثری از حلقه‌ی جاوا اسکریپتی مشاهده نمی‌شود. در اینجا چون از متد kendo.render استفاده می‌شود، نیازی به ذکر حلقه نیست و به صورت خودکار، به تعداد عناصر آرایه دریافتی از سرور، قطعه HTML قالب را تکرار می‌کند.
در ادامه برای کار با سرور از یک Kendo UI DataSource استفاده شده‌است. قسمت transport/read آن، کار تعریف محل دریافت اطلاعات را از سرور مشخص می‌کند. رویدادگران change آن اطلاعات نهایی دریافتی را توسط متد view در اختیار متد kendo.render قرار می‌دهد. در نهایت، قطعه‌ی HTML رندر شده‌ی نهایی حاصل از اجرای قالب، در بین تگ‌های ul مربوط به container2 درج خواهد شد.
رویدادگران change زمانیکه data source، از اطلاعات راه دور و یا یک آرایه‌ی جاوا اسکریپتی پر می‌شود، فراخوانی خواهد شد. همچنین مباحث مرتب سازی اطلاعات، صفحه بندی و تغییر صفحه، افزودن، ویرایش و یا حذف اطلاعات نیز سبب فراخوانی آن می‌گردند. متد view ایی که در این مثال فراخوانی شد، صرفا در روال رویدادگردان change دارای اعتبار است و آخرین تغییرات اطلاعات و آیتم‌های موجود در data source را باز می‌گرداند.


یک نکته‌ی تکمیلی: فعال سازی intellisense کدهای جاوا اسکریپتی Kendo UI

اگر به پوشه‌ی اصلی مجموعه‌ی Kendo UI مراجعه کنید، یکی از آن‌ها vsdoc نام دارد که داخل آن فایل‌های min.intellisense.js و vsdoc.js مشهود هستند.
اگر از ویژوال استودیوهای قبل از 2012 استفاده می‌کنید، نیاز است فایل‌های vsdoc.js متناظری را به پروژه اضافه نمائید؛ دقیقا در کنار فایل‌های اصلی js موجود. اگر از ویژوال استودیوی 2012 و یا بالاتر استفاده می‌کنید باید از فایل‌های intellisense.js متناظر استفاده کنید. برای مثال اگر از kendo.all.min.js کمک می‌گیرید، فایل متناظر با آن kendo.all.min.intellisense.js خواهد بود.
بعد از اینکار نیاز است فایلی به نام references.js_ را به پوشه‌ی اسکریپت‌های خود با این محتوا اضافه کنید (برای VS 2012 به بعد):
/// <reference path="jquery.min.js" />
/// <reference path="kendo.all.min.js" />
نکته‌ی مهم اینجا است که این فایل به صورت پیش فرض از مسیر Scripts/_references.js/~ خوانده می‌شود. برای اضافه کردن مسیر دیگری مانند js/_references.js/~ باید آن‌را به تنظیمات ذیل اضافه کنید:
 Tools menu –> Options -> Text Editor –> JavaScript –> Intellisense –> References
گزینه‌ی Reference Group را به (Implicit (Web تغییر داده و سپس مسیر جدیدی را اضافه نمائید.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:
KendoUI04.zip
مطالب
سازگار کردن لینک‌های قدیمی یک سایت با ساختار جدید آن در ASP.NET MVC
اگر پیشتر سایتی را در آدرس مشخصی در اینترنت داشته‌اید و اکنون تنها نرم افزار آن تغییر کرده است، اما نحوه ارائه خدمات آن خیر، لازم است بتوانید شرایط ذیل را مدیریت کنید:
- موتورهای جستجو مدام اطلاعات قبلی خود را به روز می‌کنند. اگر آدرس قبلی مقاله‌ای در سایت شما http://site/year/month/day/title بوده، برای نمونه گوگل هر از چندگاهی مجددا به این آدرس مراجعه می‌کند تا حداقل مطمئن شود وجود خارجی دارد یا خیر (این نکته را از لاگ‌های خطای سایت استخراج کردم).
- سایت‌های زیادی هستند که پیشتر به سایت شما و مطالب آن لینک داده‌اند. نمی‌توانید از آن‌ها درخواست کنید لطفا بانک اطلاعاتی خود را به روز کنید.
- اگر فید قبلی سایت شما http://site/feeds/posts بوده و اکنون چیز دیگری است، باز هم نمی‌توانید از همه درخواست کنید اطلاعات خود را به روز کنند. عده‌ای اینکار را خواهند کرد و تعداد زیادی هم خیر.

برای مدیریت یک چنین مواردی می‌توان از امکانات مسیریابی موجود در ASP.NET MVC استفاده کرد؛ که نمونه‌ای عملی از آن‌را جهت سازگاری سایت جاری با هاست قبلی آن (بلاگر) در ادامه مطالعه خواهید نمود:

الف) سازگار سازی لینک‌های قدیمی برچسب‌های سایت با ساختار جدید آن
در بلاگر آدرس‌های برچسب‌ها، به صورت http://site/search/label/name تعریف شده است. در سایت جاری برچسب‌ها توسط کنترلر Tag مدیریت می‌شوند. برای هدایت آدرس‌های قدیمی (موجود در موتورهای جستجو یا ثبت شده در سایت‌هایی که به ما لینک داده‌اند) می‌توان از تعریف مسیریابی ذیل در فایل global.asax استفاده کرد:
routes.MapRoute(
                "old_bloger_tags_list", // Route name
                "search/label/{name}", // URL with parameters
                new { controller = "Tag", action = "Index", name = UrlParameter.Optional, area = "" } // Parameter defaults
            );
به این ترتیب به صورت خودکار تمامی آدرس‌های شروع شده با http://site/search/label پالایش شده و سپس قسمت name آن‌ها جدا سازی می‌شود. این نام به متدی به نام Index در کنترلر Tag که دارای پارامتری به نام name است ارسال خواهد شد.

ب) از دست ندادن خوانندگان قدیمی فیدهای سایت
دو نوع فید کلی در بلاگر وجود دارد: http://site/feeds/posts/default و http://site/feeds/comments/default؛ اما در سایت جاری فیدها توسط کنترلری به نام Feed ارائه می‌شوند. برای سازگار سازی آدرس‌های قدیمی و هدایت آن‌ها به صورت خودکار به کنترلر فید می‌توان از دو تعریف مسیریابی ذیل استفاده کرد:
routes.MapRoute(
                "old_bloger_posts_feeds_list", // Route name
                "feeds/posts/default", // URL with parameters
                new { controller = "Feed", action = "Posts", name = UrlParameter.Optional, area = "" } // Parameter defaults
            );

routes.MapRoute(
                "old_bloger_comments_feeds_list", // Route name
                "feeds/comments/default", // URL with parameters
                new { controller = "Feed", action = "Comments", name = UrlParameter.Optional, area = "" } // Parameter defaults
            );            
در اینجا دو آدرس ذکر شده به کنترلر Feed و متدهای Posts و Comments آن هدایت خواهند شد و به این نحو کاربران قدیمی سایت هیچگونه تغییری را احساس نکرده و باز هم فیدخوان‌های آن‌ها، بدون مشکل کار خواهند کرد.

ج) پردازش لینک‌های قدیمی مطالب سایت و هدایت آن‌ها به آدرس‌های جدید
این مورد اندکی مشکل‌تر از موارد قبلی است:
routes.MapRoute(
                "old_bloger_post_urls",
                "{yyyy}/{mm}/{title}",
                new { controller = "Post", action = "OldBloggerLinks" },
                new { yyyy = @"\d{4}", mm = @"\d{1,2}" }
            );
برای نمونه آدرس مقاله‌ای مانند http://site/2012/05/ef-code-first-15.html را درنظر بگیرید. سه قسمت سال، ماه و عنوان آن، حائز اهمیت هستند. این‌ها را در اینجا به کنترلر Post و متد OldBloggerLinks آن هدایت خواهیم کرد. همچنین برای سال و ماه آن نیز قید تعریف شده است. سال عددی 4 رقمی است و ماه عددی یک تا دو رقمی.
کدهای متد OldBloggerLinks را در اینجا مشاهده می‌کنید:
        public virtual ActionResult OldBloggerLinks(int yyyy, int mm, string title)
        {
            var oldUrl = string.Format(CultureInfo.InvariantCulture, "https://www.dntips.ir/{0}/{1}/{2}", yyyy, mm.ToString("00"), title);
            var blogPost = _blogPostsService.FindBlogPost(oldUrl);
            if (blogPost != null)
                return RedirectToActionPermanent(actionName: ActionNames.Index, controllerName: MVC.Post.Name,
                                                 routeValues: new { id = blogPost.Id, name = blogPost.Title.GetPostSlug() });
            return this.Redirect("/");
        }
در اینجا چون ساختار لینک‌ها کلا تغییر کرده است، ابتدا بر اساس پارامترهای دریافت شده، لینک قدیمی بازسازی می‌شود. سپس به بانک اطلاعاتی مراجعه شده و لینک قدیمی به همراه شماره مطلب مرتبط با آن یافت می‌شود (یک فیلد oldUrl برای مطالب قدیمی در بانک اطلاعاتی وجود دارد). در آخر هم به کمک متد  RedirectToActionPermanent آدرس رسیده به آدرس جدید مطلب در سایت ترجمه و هدایت خواهد شد. Permanent بودن آن برای به روز رسانی خودکار اطلاعات موتورهای جستجو مفید است.


نتیجه گیری
به کمک امکانات مسیریابی توکار ASP.NET MVC می‌توان ساختار قدیمی یک سایت را به ساختار جدید آن ترجمه کرد. به این ترتیب لینک‌های قدیمی ثبت شده در صدها سایت اینترنتی که به سایت ما اشاره می‌کنند، مجددا بدون مشکل قابل استفاده بوده و همچنین موتورهای جستجو نیز امکان به روز رسانی اطلاعات خود را خواهند یافت.

نظرات مطالب
نمایش فرم‌های مودال Ajax ایی در ASP.NET MVC به کمک Twitter Bootstrap
پروژه سورس باز هست. به قسمت  success سورس آن دقت کنید (سطر 74 کد افزونه):
 success: function (result) {
           if (result.success) {
                  $('#dialogDiv').modal('hide');
                  if (options.completeHandler)
                     options.completeHandler();
به completeHandler فراخوانی شده، اطلاعاتی ارسال نمی‌شود.
مطابق نیاز خودتان این قسمت را تغییر داده و استفاده کنید. مثلا result دریافتی را به آن متد ارسال کنید.
مطالب
روشی سریع برای ایجاد RSS و Sitemap در ASP.NET MVC
برای مطالعه روش‌های بدست آوردن خروجی xml مربوط به Rss و Sitemap،  میتوانید از مقالات مشخص شده استفاده کنید .[اینجا] و [اینجا].

در صورتیکه طراحی شما بر اساس MVC صورت گرفته است، در کمتر از چند دقیقه و در سه مرحله میتوانید پرونده Rss و Sitemap را برای همیشه ببندید. 

پیش از تشریح مراحل، به ساختار این دو فایل توجه کنید. 

مراحل کار : 

مرحله 1. ایجاد نوع(Type) مورد نیاز برای ایجاد Xml ‌های فوق

مرحله 2 . ایجاد کنترلر XML

مرحله 3. ایجاد مسیریابی(Routing)


مرحله 1 : ابتدا یک کلاس به منظور شکل دهی به اطلاعات، بر اساس خواسته‌های xml مرتبط با RSS و Sitemap تشکیل دهید:

public class PostToXml
    {
        
        public int PostId { get; set; }

        public string title { get; set; }

        public string link { get; set; }
        
        public string description { get; set; }

        public Nullable<DateTime> pubDate { get; set; }

      
    }

مرحله 2 : یک کنترلر به نام xml ایجاد کنید و اکشن متدهای زیر را درون آن قرار دهید :

       public ContentResult RSS()
        {
            
            var items = GetRssFeed();
            var rss = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
              new XElement("rss",
                new XAttribute("version", "2.0"),
                  new XElement("channel",
                    new XElement("title", "آخرین مطالب سایت"),
                    new XElement("link", "http://" + Request.Url.Host+"/rss"),
                    new XElement("description", "آخرین مطالب سایت من"),
                    new XElement("copyright","(c)" + DateTime.Now.Year + ", نام سایت من.تمامی حقوق محفوظ است"),
                  from item in items
                  select
                  new XElement("item",
                    new XElement("title", item.title),
                    new XElement("description", item.description),
                    new XElement("link", item.link),
                    new XElement("pubDate", item.pubDate)

                  )
                )
              )
            );
            return Content(rss.ToString(), "text/xml");
        }



        public ContentResult Sitemap()
        {
            XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            var items = GetLinks();
            var sitemap = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
                new XElement(ns + "urlset",
                    from item in items
                    select
                    new XElement("url",
                      new XElement("loc", item.link),
                      new XElement("changefreq", "monthly"),
                      new XElement("priority", "0.5")
                      )
                    )
                  );
            return Content(sitemap.ToString(), "text/xml");
        }


        public IEnumerable<PostToXml> GetRssFeed()
        {
          // یک کوئری که لیستی از تایپ مشخص شده به ما بدهد
        }

         public IEnumerable<PostToXml> GetLinks()
        {
            // یک کوئری که لیستی از تایپ مشخص شده به ما بدهد
        }

این کنترلر دارای دو اکشن متد Rss و Sitemap است و این اکشن‌ها وظیفه‌ی ایجاد فایل‌های Xml را به عهده دارند. مواد اولیه این xml ‌ها از دو متد GetRssFeed و GetLinks تهیه می‌شوند. ما این مواد را در تمپلیت Rss و Sitemap جایگذاری خواهیم کرد. (به کمک دو اکشن متد Rss و Sitemap )

کافیست لیستی از مواردی را که می‌خواهیم در Rss یا Sitemap ثبت شوند، تهیه کنیم. این لیست بر اساس شکل تنظیم دیتابیس و مسیریابی سایت، می‌تواند پیچیده و یا ساده باشد. (به کمک کوئری گرفتن با linq و یا اضافه کردن مستقیم آدرس‌ها به لیست و یا ترکیبی از هر دو مورد) برای درک بهتر موضوع، لطفا تصویر موجود در ابتدای مقاله را مشاهده نمایید.

مرحله 3 : در مرحله آخر کافیست دو مورد زیر را به فایل RoutConfig.cs بیافزایید: 

routes.MapRoute(
              "Sitemap", "sitemap",
              new { controller = "XML", action = "Sitemap" });
 routes.MapRoute(
              "RSS", "rss",
               new { controller = "XML", action = "RSS" });

به کمک آدرس‌های زیر می‌توانید به آنچه که تهیه کرده‌اید دسترسی داشته باشید :

http://domain.com/rss
http://domain.com/sitemap  

فایل پروژه را دریافت کنید :

MVC_RSS_Sitemap-43ad3c6681734b34b91deaaabcdba871.rar