[ASP.NET MVC Mavericks road] 14 - Unobtrusive Ajax

Ajax (abbreviation for Asynchronous JavaScript and XML), as we can see, the focus of this concept is no longer the XML part, but the Asynchronous part. It is a model that requests data from the server in the background. MVC framework has built-in support for Unobtrusive Ajax, which allows us to define the characteristics of Ajax through MVC's help motif without mixing a large piece of JavaScript code in View.

Common Ajax usage

Before talking about Unobtrusive Ajax in MVC, let's take a look at the common use of Ajax in MVC. Readers can compare and learn when reading the following articles.
Create a new MVC application (basic template), add a controller named Home, add a view for the automatically generated Index action, and edit the index The cshtml code is as follows:

@{
    ViewBag.Title = "Index";
}

<script type="text/javascript">
    function test() {
        $.ajax({
            url: '@Url.Action("GetTestData")',
            type: "POST",
            success: function (result) {
                $("#lblMsg").text(result.msg);
            }
        });
    }
</script>

<h2 id="lblMsg"></h2>
<input type="button" value="test" onclick="test();" />

Add an action named Test in HomeController, as follows:

public JsonResult GetTestData() {
    return Json(
        new { msg = "Datetime from server: " + DateTime.Now.ToString("HH:mm:ss") }
    );
}

Run the program and click the test button. We can see the time of getting back from the background with Ajax:

The time will refresh every time you click the test button. Here's a point to remind you. In this example, $ The ajax() method uses the POST request. If you want to use the GET request, the Json method in Test action needs to set the value of JsonRequestBehavior to AllowGet (default is DenyGet), as follows:

public JsonResult GetTestData() {
    return Json(
        new { msg = "Datetime from server: " + DateTime.Now.ToString("HH:mm:ss") },
        JsonRequestBehavior.AllowGet
    );
}

In addition, after changing to GET request, click the test button for many times, and the time will not be refreshed. This is because the GET request is in ASP Net, for the same URL request, the data in the cache is returned.

What is Unobtrusive Ajax

Unobtrusive Ajax is a common way to use JavaScript in Web pages. The term is not clearly defined, but it has the following basic principles (from Wikipedia):

  • Behavior (JavaScript code) is separated from the structure (Html markup) and presentation (CSS style) of Web pages.
  • The best implementation of JavaScript solves the traditional problems of JavaScript language itself (such as lack of scalability and inconsistent coding style of developers).
  • Resolve browser compatibility issues.

To deepen your understanding, look at a piece of code in the "structure" section of one of the Unobtrusive Ajax below:

...
<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" id="form0" method="post">
...

This is called Ajax. after MVC opens Unobtrusive JavaScript. The code generated by the beginform method. This code is completely separated from JavaScript. Html tags tell JavaScript what kind of behavior it has through some tags. None of the code in the separated JavaScript file (jquery.unobtrusive-ajax.min.js file introduced in MVC) is specially written for a Html element in a specific Web page, that is, all functions are common. This is the core idea of Unobtrusive Ajax.

Compared with the common way of using Ajax, Unobtrusive Ajax is easier to read, enhances scalability and consistency, and is easy to maintain.

Using MVC Unobtrusive Ajax

To use Unobtrusive Ajax in MVC, you must first "turn it on", which requires two actions. One is to configure the web in the root directory In the config file, set the unobtrusive JavaScript enabled value under the configuration/appSettings node to true, as shown below:

... 
<configuration> 
    <appSettings> 
        ...
        <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
    </appSettings> 
</configuration> 
... 

The value of unobtrusive JavaScript enabled defaults to true when the program is created. Sometimes it only needs to be checked during development. The second action is to introduce the jquery library and jquery into the View that needs to use MVC Unobtrusive Ajax unobtrusive-ajax. Min.js file, which is generally more common in / Views/Shared/_Layout.cshtml, as follows:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

Now let's do an example of using Unobtrusive Ajax to get a simple user list from the server. To do this, we need to prepare a Model as follows:

namespace MvcApplication1.Models {
    public class Person {
        public string ID { get; set; }
        public string Name { get; set; }
        public Role Role { get; set; }
    }

    public enum Role {
        Admin, User, Guest
    }
}

I'm usually used to writing background methods first and then UI. Create a controller named People, write the action to be used in the controller, and the code is as follows:

public class PeopleController : Controller {
    public class PeopleController : Controller {
        private Person[] personData = { 
            new Person {ID = "ZhangSan", Name = "Zhang San", Role = Role.Admin}, 
            new Person {ID = "LiSi", Name = "Li Si", Role = Role.User}, 
            new Person {ID = "WangWu", Name = "Wang Wu", Role = Role.User}, 
            new Person {ID = "MaLiu", Name = "Ma Liu", Role = Role.Guest}
        };

        public ActionResult Index() {
            return View();
        }

        public PartialViewResult GetPeopleData(string selectedRole = "All") {
            IEnumerable<Person> data = personData;
            if (selectedRole != "All") {
                Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
                data = personData.Where(p => p.Role == selected);
            }
            return PartialView(data);
        }

        public ActionResult GetPeople(string selectedRole = "All") {
            return View((object)selectedRole);
        }
    }
}

The GetPeopleData action method is added here. The user data is obtained according to the selectedRole and passed to the PartialView method.

Next, create a partial view: / views / people / getpeopledata for GetPeopleData action Cshtml, the code is as follows:

@using MvcApplication1.Models
@model IEnumerable<Person>

@foreach (Person p in Model) {
    <tr>
        <td>@p.ID</td>
        <td>@p.Name</td>
        <td>@p.Role</td>
    </tr>
}

Then create our home view / views / people / getpeople Cshtml, the code is as follows:

@using MvcApplication1.Models
@model string

@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody"
    };
}

<h2>Get People</h2>
<table>
    <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
    <tbody id="tableBody">
        @Html.Action("GetPeopleData", new { selectedRole = Model })
    </tbody>
</table>
@using (Ajax.BeginForm("GetPeopleData", ajaxOpts)) {
    <div>
        @Html.DropDownList("selectedRole", new SelectList(
            new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
        <button type="submit">Submit</button>
    </div>
}

First, an Ajax options object is created, and its properties (such as UpdateTargetId, Url, HttpMethod, etc.) can set how Ajax requests. These attributes can be seen by name. For example, UpdateTargetId indicates the element to be refreshed after calling the Ajax request (specified by element ID). Then include the form that needs to be submitted to the server in Ajax Submit the data to the server through the submit () method.

In order to make the operation more beautiful, we are_ Layout. Add some styles to the table element in the cshtml file, as follows:

... 
table, td, th { 
    border: thin solid black; border-collapse: collapse; padding: 5px; 
    background-color: lemonchiffon; text-align: left; margin: 10px 0; 
}
...

Run the program, locate the URL to / People/GetPeople, and click the submit button on the page. The effect is as follows:


Ajax.BeginForm sends ajax requests to the server by submitting forms. ajax can also be used in MVC The actionlink () method generates a link to send an ajax request to the server. Let's go to getpeople Add this request method in cshtml view:

<div> 
    @foreach (string role in Enum.GetNames(typeof(Role))) { 
        @Ajax.ActionLink(role, "GetPeopleData",  new {selectedRole = role}, 
            new AjaxOptions {UpdateTargetId = "tableBody"}) @:&nbsp;
    } 
</div>

The effect is the same as before:

Ajax.ActionLink() and Ajax The difference between beginform() and the former is that the former can only transmit data to the server through the Url parameter.

How Unobtrusive Ajax works

How does Unobtrusive Ajax work?

When calling Ajax After the beginform method, the attributes set through the Ajax options object will be converted into the attributes (tags) of the form element. These attributes start with data ajax, as shown in the form element generated in this example:

<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" id="form0" method="post">
...

When getpeople When the cshtml view is loaded and the Html page is rendered, jQuery unobtrusive-ajax. JS library looks for all elements whose data ajax attribute value is true, and then according to other attribute values starting with data ajax, the functions in jQuery library will know how to execute Ajax requests.

Configuring Ajax options

The properties in the Ajax options class tell the MVC framework how to generate JavaScript and Html code related to Ajax requests. It contains the following attributes:

There are good explanations for the intelligent prompts of these attributes VS. here we will not talk about them one by one, but only select a few representative ones.

AjaxOptions.Url property

In the above example, we are in Ajax The action name parameter is specified in the beginform() party, and MVC helps us generate the Url of the Ajax request (action = "/ People/GetPeopleData"). There is a problem with this. When the browser disables JavaScript, clicking the submit button will generate a new request (non Ajax request / People/GetPeopleData), so that the data returned by the server will directly replace the original page. To solve this problem, you can use ajax options Url attribute because Ajax options The Url attribute generates another Url that is specifically used for Ajax requests. Here's how we describe / views / people / getpeople Cshtml can be modified simply:

...
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData")
    };
}
...
@using (Ajax.BeginForm(ajaxOpts)) {
    ...
}

After running, we see the same results as before, indicating that there is no difference in effect. But the form attribute it generates is different:

<form id="form0" action="/People/GetPeople" method="post" data-ajax-url="/People/GetPeopleData" data-ajax-update="#tableBody" data-ajax-mode="replace" data-ajax="true"> 
...

It generates two URLs, the values of the action attribute and the data ajax Url attribute. The former is Ajax The beginform () method is generated based on the current controller and action name, which is generated by the Url attribute of Ajax options. When the browser does not disable JavaScript, the Unobtrusive Ajax JS library will obtain the value of the data ajax Url attribute as the Url to make an Ajax request. When JavaScript is disabled in the browser, the value of the natural action attribute determines the Url representing the submission, and the server will return to the original whole page. Although some parts fail to refresh, it will not make users feel that the website is doing badly.

Ajax loads data while giving feedback to users

When loading data takes a long time, in order to avoid false death, a feedback message should be given to the user, such as "loading...". In the Unobtrusive Ajax of MVC, this can be easily done through the two properties of LoadingElementId and LoadingElementDuration of Ajax options. Modify getpeople Cshtml is as follows:

@using MvcApplication1.Models
@model string

@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 1000,
    };
}
<h2>Get People</h2>
<div id="loading" class="load" style="display:none">
    <p>Loading Data...</p>
</div>
...

No explanation, run the program to see the effect:

A confirmation dialog box pops up

It's also convenient to use Unobtrusive Ajax in MVC to pop up the confirmation dialog box. Set Ajax options The value of the confirm attribute can be as follows:

...
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 1000,
        Confirm = "Do you wish to request new data?" 
    };
}
...

The dialog box that pops up is as follows:

Ajax callback function

The OnBegin, OnComplete, OnFailure and OnSuccess attributes in the ajax options class allow us to define callback functions at a certain state point in the ajax request cycle. Look at the specific usage.

In getpeople The following four callback functions are added to the cshtml file:

<script type="text/javascript"> 
    function OnBegin() { 
        alert("This is the OnBegin Callback"); 
    }
    function OnSuccess(data) { 
        alert("This is the OnSuccessCallback: " + data); 
    } 
    function OnFailure(request, error) { 
        alert("This is the OnFailure Callback:" + error); 
    } 
    function OnComplete(request, status) { 
        alert("This is the OnComplete Callback: " + status); 
    } 
</script>

Then set the four event properties of the Ajax options object:

...
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        OnBegin = "OnBegin", 
        OnFailure = "OnFailure", 
        OnSuccess = "OnSuccess", 
        OnComplete = "OnComplete"
    };
}
...

Run the program and three message boxes pop up as follows:



Among the four event attributes, OnSuccess and OnFailure are the most commonly used. For example, we often process the returned Json data in the OnSuccess callback function.

In fact, I personally prefer the ordinary way of using Ajax. Ajax.BeginForm() and Ajax Actionlink () uses less and is used to HTML Beginform() or HTML Actionlink () and handwritten jQuery ajax code instead.

Keywords: ASP.NET Ajax mvc

Added by andysez on Wed, 02 Mar 2022 16:20:14 +0200