Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Ajax and JavaScript

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

Using AJAX to Update Content

In many cases, you'll want to use various jQuery AJAX functions to update visible Web-site content. Some content updates may be based on the user information for the current user, other updates may be based on requests performed by any user, such as information based on a search performed by the Web-site visitor.

Let's look at some techniques for using jQuery's AJAX methods to update content.

Getting Content Based on the Current User

If you have been developing Web sites even for the shortest period of time, you are likely aware of query strings in the URL. Unless Web-site developers are using methods to hide the strings, you may have seen something similar to this:

Everything past the question mark is a query string that can be used in a GET request to the server. Each item is set up in a name=value pair, which can be easily parsed by scripting languages like jQuery and PHP.

GET requests are not limited to the URL. You can use GET as a form method or in AJAX. jQuery provides a shorthand method call for making this kind of request to the server, and conveniently, it is called get.

  1. Open chap4/4-2.php to set up a get function to retrieve the current user's pictures into the Web browser. Rather than storing the jQuery code in a different file and including it, let's use a slightly different technique that is very valuable when small jQuery scripts are used.
  2. Locate the closing </body> tag. Just before that tag, the jQuery AJAX get method will be set up to retrieve the user's pictures. Begin by inserting the script tag:
    <script type="text/javascript">
  3. Open the function by making sure that the document (the current Web page DOM information) is completely loaded:
        $(document).ready(function() {
  4. The first critical step in making sure that you get the right information from the database is to assign the value of the cookie set during login to a variable that can be used by jQuery. The information in the cookie is the user's name:
          var cookieUser = '<?php echo $_COOKIE['photoex'];?>';
  5. As stated earlier, the get method relies on name=value pairs to do its work properly. Make sure that the get request sends the cookie data to the server as a name=value pair:
            $.get('inc/userPhoto.php', {photoUser: cookieUser}, function(data){
  6. Load the information returned into the div with an id of myPhotos:
  7. Close the get function with the data type that is expected to be returned from the PHP script. Once closed, set the closing </script> tag (the </body> tag is shown only for reference):
            }, 'html');
  8. Before you can get the photos from the database, you need to create the photo table. So, run the pephoto.sql file located in the chap4/sql folder of the code download. The SQL file will also insert default data for the photos located in the chap4/photos folder.

    In the PHP file chap4/inc/userPhoto.php, the SQL query uses the information contained in the photoUser variable:

    $getImg = "SELECT `imgName`,`imgThumb` ";
    $getImg .= "FROM `photoex`.`pephoto` ";
    $getImg .= "WHERE `username` = '".$_GET['photoUser']."' ";

    The user's photographs are retrieved and placed into a table for viewing. The results are illustrated in Figure 4.6.

    Figure 4.6

    Figure 4.6 The user's photographs in tabular form.

Combining user data with the get method is very effective for pages where data unique to the user must be displayed. What about content that is not unique to the user? The get method has a cool little brother called load.

Loading Content Based on Request

Of the jQuery AJAX shorthand methods, load is the simplest and easiest method for retrieving information from the server. It is especially useful if you want to call on new information that does not need data passed to it like you would do with the get or post methods. The syntax for load is short and sweet as well:


Clicking on the Write link (Figure 4.7) invokes the load function, causing chap4/inc/userWrite.php to be loaded into the div with an id of newArticle.

Figure 4.7

Figure 4.7 The form has been loaded into the page so that the user can write a new article.

There is one other really neat feature that load offers: You can use it to bring in just portions of other pages. For instance, to bring in a div with an id of part1 from another page, the syntax is as follows:

$('#newArticle').load('inc/anotherPage.html #part1');

Having the option of loading page portions can give you a great deal of design and organizational flexibility.

Not every Web site can use every AJAX feature that jQuery offers, so you'll leave the Photographer's Exchange Web site behind at this point. You'll develop stand-alone examples to demonstrate some of the other features and events available in jQuery's AJAX library.

Loading Scripts Dynamically

There are some cases in which you will need to load JavaScript or jQuery scripts just for one-time use in your Web pages and applications. jQuery provides a special AJAX shorthand method to do just that, getScript.

For this example, you'll use the code contained in chap3/dvdCollection, which is a small personal Web site designed to be used as a catalog of all the DVD and Blu-ray Discs that you own.

From time to time, you'll want to know just how many DVD and Blu-ray Discs you have, but it isn't really necessary to load the script that performs the counts and displays the result every time you use the site. jQuery's getScript method is the perfect remedy for loading scripts that you'll use infrequently.

  1. Set up a script called dvdcount.js and place it in the inc directory of the DVD collection site. This is the script that getScript will load when called upon to do so.
  2. Include the document ready functionality:
  3. Each movie is contained in a div with a class of dvd. Assign the count of those div's to the variable totalCount:
        var totalCount = $('.dvd').length;
  4. Use jQuery's :contains selector to help count the types of discs in the collection. The :contains selector is very handy for finding elements containing a specific string. Here it is used to find the text "DVD" or "Blu-ray" in the h3 element:
       var dvdCount = $('h3:contains("DVD")').length;
        var brCount = $('h3:contains("Blu-ray")').length;
  5. Set up the modal window to show the user the information. This is the same technique used in Chapter 2 and Chapter 3, so I won't cover each step in detail:

       var movieModal = '<div class="movieModal">Total Movies: '+totalCount+'<br />DVD: '+dvdCount+'<br />Blu-ray: '+brCount+'</div>';
        var modalMarginTop = ($('.movieModal').height() + 40) / 2;
        var modalMarginLeft = ($('.movieModal').width() + 40) / 2;
            'margin-top' : -modalMarginTop,
            'margin-left' : -modalMarginLeft

    The modal will only pop up for a moment before fading out:

       $('.movieModal').fadeIn('slow', function(){
            $(this).fadeOut(2500, function() {

The main page for the DVD catalog site is chap4/dvdCollection/4-5.php. Let's take a moment to set it up.

  1. Enter the information for the header:
    <!DOCTYPE html>
    <html lang="en">
            <meta charset="utf-8">
            <title>DVD Collection Catalog</title>
            <link rel="stylesheet" href="css/dvd.css" type="text/css" />
  2. Include the jQuery file so that all of the interactions will run properly:
           <script type="text/javascript" src="inc/jquery-1.5.min.js"></script>
  3. Set up the body next:
        <h2>DVD Collection Catalog</h2>
        <div class="menuContainer">
  4. Set up the menu section carefully, because you'll use these elements to call other scripts:
          <ul class="menu">
                <li id="add">Add</li>
                <li id="summary">Summary</li>
        <br />
  5. Set up the div that will house the content of the page:
        <div class="content"></div>
  6. Create the section containing the jQuery scripts you'll use to load information into the page along with the function that loads chap4/dvdCollection/inc/getdvd.php. The PHP is called by the jQuery load method to get the information about the DVD collection:
       <script type="text/javascript">
  7. Bind the click method to the list item with an id of summary. This will call getScript to run the jQuery script created earlier, dvdcount.js:
               $('#summary').click(function() {
  8. Close out the HTML:

Clicking the Summary element on the Web page causes the dvdcount.js script to be loaded and run, showing the modal window complete with counts (Figure 4.8). The modal window then slowly fades away.

Figure 4.8

Figure 4.8 Clicking on the Summary element loads and runs the script.

You will find many cases where loading and running scripts on the fly will enhance your Web sites and applications.

Next, you'll turn your attention to many of jQuery's AJAX extras and learn how to apply them practically.

Using jQuery's AJAX Extras

In addition to the shorthand methods, jQuery provides many useful methods and helpers to give you ways to use AJAX efficiently. These methods range from low-level interfaces to global event handlers, all of which, when applied properly, will make your programs and Web sites more effective.

Let's look at these extras, starting with the low-level interfaces.

Working with Low-Level Interfaces

jQuery's low-level AJAX interfaces provide the most detailed approach to AJAX functions. This kind of detail makes the low-level interfaces quite flexible but introduces additional complexity due to all of the options available.

One way to combat the complexity of having an extensive choice of options is to use a method to set up options that do not change frequently. Take a look at the simplest of the low-level interfaces, ajaxSetup:

    url: ajaxProcessing.php,
    type: 'POST'

The ajaxSetup method allows you to provide options that will be used with every AJAX request. You can set all of the AJAX options available (over 25 of them!) using ajaxSetup. This is very convenient if you need to make repeated AJAX requests to the same URL or use the same password each time you make a request. In many cases, developers will put all of their server-side AJAX handlers in the same file on the server. Using ajaxSetup shortens their AJAX calls, including the shorthand methods. Given the current example of ajaxSetup, your post method could be configured like this:

$.post({ data: formData });

The only thing you need to supply to the post function is the data to be handled by ajaxProcessing.php. One advantage of using the ajaxSetup method is that you can override any of the ajaxSetup options in the individual AJAX calls that you make.

The low-level interface that you will see in use most is the straight ajax method. It is the function that is wrapped by the shorthand methods and is at the very heart of all of jQuery's AJAX calls. The ajax method is capable of accepting all of the options that can be used with jQuery's AJAX requests. Perhaps the best way to understand the low-level AJAX method is to compare it to one of the shorthand methods you used earlier. Here is the post method that you used to check to make sure the user name was available:

$.post('inc/peRegister.php', {
    formName: 'register',
    penewuser: newName
}, function(data){
    var usernameCount = data;
    if(1 == usernameCount){
        $('#penewuser').next('.error').css('display', 'inline');
    } else {
        $('#penewuser').next('.error').css('display', 'none');
}, 'html');

Here is the same request using jQuery's low-level ajax method:

    type: 'POST',
    url: 'inc/peRegister.php',
    data: 'formName=register&penewuser='+newName+'',
    success: function(data){
        var usernameCount = data;
        if(1 == usernameCount){
            $('#penewuser').next('.error').css('display', 'inline');
        } else {
            $('#penewuser').next('.error').css('display', 'none');
    dataType: 'html'

The differences are fairly obvious, such as declaring the method that AJAX should use to convey the information to the server (type: 'POST'), specifying the way that raw data is formatted (data: 'formName=register&penewuser='+newName+'',) and ensuring that the success method is implicitly defined (success: function(data){...).

Take a tour of jQuery's ajax API at to see all of the options available for use with this method.

Now that you can send information to the server and receive information back from your server-side processes, you need to make sure that your users are informed that an AJAX action is taking place. jQuery provides several helper functions that make it easy for you to do just that.

Triggering Events Before and After the AJAX Call

In many cases, your jQuery AJAX functions will happen so quickly that users may not even know that their actions achieved the desired result. In other cases, the AJAX process may be lengthy and require that users wait for results. jQuery provides four methods that you can use to keep users informed: ajaxStart, ajaxSend, ajaxComplete, and ajaxStop.

It is important to understand that there is an order to these four functions. You can call any number of AJAX processes during any given event. For this reason, you may want to know not only when the first AJAX function starts, but also when each subsequent AJAX method gets called and completes. Then you may want to register that all of the AJAX calls have completed. If you imagine jQuery AJAX events as a stack of items as in Figure 4.9, you'll see how the jQuery AJAX engine defines the order of the events and their calls.

Figure 4.9

Figure 4.9 The initial jQuery events are stacked up by the developer and then ordered and processed by jQuery's AJAX engine.

Let's take a close look at how to use the ajaxStart and ajaxStop methods by giving users a visual queue during a data- and file-submission event in the DVD Collection Catalog.

  1. Open chap4/4-6.php.

    In 4-6.php you will see a form (Figure 4.10 on the next page) that accepts user input and provides a method for uploading a file. This combination is not unusual, but it will require that you pay careful attention when writing the PHP and jQuery to handle the data transfer and file upload.

    Figure 4.10

    Figure 4.10 The form that users will fill out to add movies to their personal database.

    Two PHP scripts will handle the data supplied in the form: one for the movie cover art upload (not really AJAX, remember?) and one for the data input into the form.

  2. Create a file called chap4/dvdCollection/inc/dvdcover.php to set up the image upload first.
  3. Set up the path for the cover art:
    $coverPath = "../cover_art/";
  4. Make sure that the file is submitted properly and has no errors:
    if ($_FILES["movieCover"]["error"] == UPLOAD_ERR_OK) {
  5. Set up the variables to hold the information about the uploaded file (this is the same technique that you used for file uploads in Chapter 3):
     $tmpName = $_FILES["movieCover"]["tmp_name"];
        $coverName = $_FILES["movieCover"]["name"];
  6. Create the regular expression used to check the file extension of the uploaded file:
        $regexFileExt = "/\.(jpg|jpeg|png)$/i";
  7. Test the file extension to see if it matches one allowed by the regular expression:
      if(preg_match($regexFileExt, $coverName)){
  8. Check the file again by making sure it really is the right kind of file according to its first few bytes:
         $arrEXIFType = array(IMAGETYPE_JPEG, IMAGETYPE_PNG);
            if(in_array(exif_imagetype($tmpName), $arrEXIFType)){
  9. Set up the file's new name and path, and place them into the variable $newCover:
             $newCover = $coverPath.$coverName;
  10. Move the properly named file to its permanent directory:
               move_uploaded_file($tmpName, $newCover);

Now that you've completed the PHP script for the file upload, you can create the PHP script that will be called by the jQuery AJAX post method to update the database.

  1. Create a file called postdvd.php and store it in the chap4/dvdCollection/inc folder.

    Only two actions are contained in postdvd.php: one to connect to the database and one to run the query that will perform the database update.

  2. Set up the database connection first (be sure to use the user name and password that you have set up for your database):
    if(!$dbc = mysql_connect('localhost', 'username', 'password')){
        echo mysql_error() . "\n";
  3. Introduce a little sleep timer to slow down the process. This will allow the animated loading graphic to be displayed by ajaxStart in the jQuery function that will be created (typically, the database operation is very fast—so fast that the user may not realize that something has occurred.):
  4. Create the SQL query that will accept the values from the AJAX post method to update the database with:
    $insertMovie = "INSERT INTO `dvdcollection`.`dvd` ";
    $insertMovie .= "(`name`,`genre`,`format`,`description`,`cover`) ";
    $insertMovie .= "VALUES(";
    $insertMovie .= "'".$_POST['movieName']."',";
    $insertMovie .= "'".$_POST['movieGenre']."',";
    $insertMovie .= "'".$_POST['movieFormat']."',";
    $insertMovie .= "'".$_POST['movieDescription']."',";
    $insertMovie .= "'cover_art/".$_POST['movieCover']."' ";
    $insertMovie .= ")";
  5. Call the mysql_query function to run the SQL query:
    if(!($movieInfo = mysql_query($insertMovie, $dbc))){
        echo mysql_error();
        echo mysql_errno();

With the PHP scripts complete, you can now turn your attention to the jQuery functions. All of the jQuery functions will be placed into the file inc/movieUp.js.

  1. Start the file by defining the ajaxStart method:


    The ajaxStart function will be called as soon as an AJAX request is made. The method can be bound to any element available in the DOM and is bound to the body element for use here. You can define any processes that you want within the ajaxStart method.

  2. For this file and data upload, create a modal pop-up window to give the users a visual clue that something is occurring:

             var waitingModal = '<div class="waitingModal"><img src="grfx/loading.gif" border="0" /></div>';
        var modalMarginTop = ($('.waitingModal').height() + 40) / 2;
        var modalMarginLeft = ($('.waitingModal').width() + 40) / 2;
            'margin-top' : -modalMarginTop,
            'margin-left' : -modalMarginLeft

    The technique used to create the modal window is no different than what you have used previously in the book.

  3. Bind the ajaxStop method to the body element (remember that methods like ajaxStart and ajaxStop can be bound to any element). When the AJAX request is complete, you'll want to clear the form and remove the modal from view so that the user knows the process is finished:
  4. Clear the form elements so that the user can use the form to add another movie. Just like using ajaxStart, you can define any process within the ajaxStop function:

       $('#addMovie input[name*="movie"]').val('');
        $('#addMovie textarea').val('');

    Be very specific with your jQuery selectors when choosing which form elements to clear. For example, using just $('#addMovie input') will also clear the form's buttons, and that would confuse the user.

  5. Fade away the modal indicator and remove it from the DOM. This is the last part of the process defined in the ajaxStop method:
      $('.waitingModal').fadeOut('slow', function(){
  6. Begin the form handler by binding the form addMovie to the submit method:
  7. Upload the image using the iframe method that was defined in Chapter 3:
        var iframeName = ('iframeUpload');
        var iframeTemp = $('<iframe name="'+iframeName+'" src="about:blank" />');
        iframeTemp.css('display', 'none');
            action: 'inc/dvdcover.php',
            method: 'post',
            enctype: 'multipart/form-data',
            encoding: 'multipart/form-data',
            target: iframeName
  8. Once the image upload is complete, remove the iframe from the DOM:
        }, 1000);
  9. Prepare the data to be used in the post method. Because information in a textarea cannot be serialized with normal jQuery methods, create a text string that sets up the textarea value as if it were serialized by making the information a name=value pair:
             var coverData = '&movieCover=' + $('input[name="movieCover"]').val();
  10. Serialize the remainder of the form data:
             var formData = $(this).serialize();
  11. Once the form data has been processed by the serialize function, concatenate the two strings together in the uploadData variable:

             var uploadData = formData + coverData;
  12. Call the jQuery AJAX shorthand method post to upload the data:
      $.post('inc/postdvd.php', uploadData);

    When the movie data form is submitted, the jQuery AJAX engine will see that there is a post occurring during the process, triggering the ajaxStart method. Figure 4.11 shows the modal loading indicator called by ajaxStart.

    Figure 4.11

    Figure 4.11 The method has called the waiting indicator.

    Once the post process has completed, the ajaxStop method is triggered, causing the modal waiting indicator to fade out.

Now that you have learned to handle AJAX calls and the data they return, you need to learn how to handle one of the Web's fastest-growing data types, JSON.

Using JSON

JSON (JavaScript Object Notation) has become a popular and lightweight way to transmit data packages for various uses over the Internet. In many ways, JSON is more popular than XML for delivering data quickly and efficiently. JSON data can be easily used with the jQuery AJAX shorthand method especially designed to handle the JSON data type, getJSON.

So what exactly is JSON?

To understand JSON, you need a little lesson in JavaScript's object literal notation. Object literal notation is an explicit way of creating an object and is the most robust way of setting up a JavaScript object. Here is an example:

var person = {
    name: "Jay",
    occupation: "developer",
    stats: ["blonde", "blue", "fair"],
    walk: function (){alert( 'is walking');}

The person object has been literally defined as name: value pairs, including a nested array (stats) and a method to make the object walk. It is a very tidy way to describe an object.

The following commands interact with the person object:

person.walk(); //alerts 'Jay is walking'
alert(person.stats[1]); // alerts 'blue'

JSON is a subset of the object literal notation, essentially the name: value pairs that describe an object. A JSON array can contain multiple objects. The key to being successful with JSON is making sure that it is well-formed. JSON must have matching numbers of opening and closing brackets and curly braces (the braces must be in the correct order); the names and values in the name : value pairs must be quoted properly; and commas must separate each name: value pair.

To illustrate this, look at the JSON for the person object:

var myJSONobject = {"person":[{

It's important to note that the JSON object does not contain any methods or functions that can be executed. JSON specifically excludes these from the notation because JSON is only meant to be a vehicle for transmitting data.

Setting Up a JSON Request

Twitter has undoubtedly become one of the most popular social media outlets since the dawn of the Internet. Twitter has made an API available for those who want to extend the use of Twitter to their own Web pages and applications. One of the most popular uses of the Twitter API is to include recent tweets in personal Web sites and blogs.

Taking advantage of the API can be as simple or as complex as you want it to be. Let's build a simple widget to obtain your last ten tweets for inclusion in a Web page.

The tweet data is returned from Twitter in the JSONP format. JSONP is known as "JSON with Padding." Under normal circumstances, you cannot make AJAX requests outside of the domain the request originates from (Figure 4.12 on the next page). JSONP relies on a JavaScript quirk: <script> elements are allowed to make those cross-domain requests.

Figure 4.12

Figure 4.12 The only way you can make a cross-domain request is with JSONP.

To make this work, the JSON must be returned in a function. Using the JSON object created earlier, the JSONP would look like this:

   myJSONfunction({"person":[{"name":"Jay", "occupation":"developer","stats":[{"hair":"blonde","eyes":"blue","skin":"fair"}]}]});

If it looks like gibberish to you now, don't worry; as you walk through the function being built to get JSON data from Twitter, it will become much clearer.

Let's build the entire file, including CSS, from scratch.

  1. Create a file called 4-7.php in the chap4 folder.
  2. Set up the DOCTYPE and include the basic head, title, and character set declarations:
    <!DOCTYPE html>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Twitter Widget</title>
  3. Provide a reference to the jQuery source that you will be using. Make sure that the path is correct; in this case the path is inc/jquery-1.5.2.min.js:
       <script type="text/javascript" src="inc/jquery-1.5.min.js"></script>
  4. Create the style information for the Twitter widget:
       <style type="text/css">
            body {
                background-color: #FFFFCC;
            #tw {
                position: relative;
                width: 350px;
                left: 50%;
                margin-left: -175px;
            .tweet {
                font-family: "Lucida Grande","Arial Unicode MS", sans-serif;
                width: 350px;
                background-color: #99FFCC;
                padding: 5px;
                border-right: 2px solid #66CC99;
                border-bottom: 3px solid #66CC99;
                margin-bottom: 2px;
  5. Close out the head section of the page:

The body section for the widget is very simple: Add a div with an id of tw to which the tweets will be appended:

        <div id="tw"></div>

The jQuery script to get the tweets is very short but requires that you pay attention to detail. You will make the names and hash tags clickable so that they have the same functionality they have on the Twitter Web site. Any links included in a tweet will also be clickable, opening a new browser window to show the information.

  1. Start the jQuery function by opening a script tag and inserting the document-ready function:
            <script type="text/javascript">
            $(document).ready(function() {
  2. Create the URL to access Twitter and store the URL in the variable twitterURL:

             var twitterURL ='';

    Be sure to replace YOUR_TWITTER_USER_NAME with your actual Twitter user name. It is very important to make sure that the URL is formatted with the query string (name=value pairs) that will be used by getJSON during the request. Send three options to Twitter: your Twitter screen_name, the count of the number of tweets to return, and most important, the callback. It is the callback option that lets Twitter know that you expect the return data to be JSONP.

  3. Once the URL is formed, open the getJSON request method by sending the URL and defining the getJSON callback option:
              $.getJSON(twitterURL, function(data){
  4. The JSONP has been returned from Twitter at this point. Set up a loop through the data contained in the function. Treat the data as members of an array called item:
                $.each(data, function(i, item){
  5. Contain the tweet in a name: value pair with the name of text. Assign this item to the variable tweetText:
             var tweetText = item.text;
  6. Use regular expressions to locate URLs, @ tags, and hash(#) tags in the tweet so that you can give each the proper treatment. Look for URL's first:

                   tweetText = tweetText.replace(/http:\/\/\S+/g, '<a href="$&" target="_blank">$&</a>');

    The regular expression /http:\/\/\S+/g matches text beginning with http:// and ending in a space, which would typically indicate a URL. The /g (global) says to match all URLs in the string contained in tweetText. The URLs are turned into links by replacing the URL with an anchor tag containing the URL as both the href and the text of the link. In JavaScript the $& property contains the last item matched by a regular expression. Because the URL was the last item matched, it can be replaced into an anchor tag by using the $& property.

  7. Twitter prefixes user names with the @ symbol. So, search tweetText for words beginning with the @ symbol:

                     tweetText = tweetText.replace(/(@)(\w+)/g, ' $1<a href="$2" target="_blank">$2</a>');

    Here, the regular expression /(@)(\w+)/g indicates that all words beginning with the @ symbol are replaced by the appropriate anchor tag to open a browser window for users' tweets. The $1 and $2 contain the information matched in each parenthesis, which is used to include those matches in the replacement text.

  8. Turn your attention to the hash tags now and use a technique similar to the one you used for replacing the @ symbol:
                   tweetText = tweetText.replace(/(#)(\w+)/g, ' $1<a href="$2" target="_blank">$2</a>');
  9. Once the tweetText has been completely manipulated to insert all of the anchor tags, place it into a div. Then append the new div to the existing div (id="tw") that was set up as part of the original content for the page:
                  $("#tw").append('<div class="tweet">'+tweetText+'</div>');
  10. Close out the jQuery function and HTML tags for the page:
  11. Upload the page to a server, and load the page into a browser. You should achieve the results that you see in Figure 4.13.
    Figure 4.13

    Figure 4.13 The Twitter widget retrieves the last few posts that you made.

With all of the data traveling back and forth between clients and servers, including servers not under your control, it is only natural to be concerned about the security of the information that you and your Web-site visitors send in AJAX requests. Let's address those concerns next.

  • + Share This
  • 🔖 Save To Your Account