PHP and JavaScript Interaction: Storing Data in the Client, part 3

In the final article in our series about using PHP and JavaScript to store data on the client side, we will be building on what we learned about server and client interaction to create a JavaScript-based paginating system.

Introduction

Welcome to the final part of the series “PHP and JavaScript Interaction: Storing Data in the Client.” Definitely, it’s been a highly satisfactory experience to deeply explore the possibilities of the PHP-JavaScript interaction process, which offers a wide range of possible applications in Web projects.

While the subject is far too extensive for being completely treated in a couple of articles, from my point of view, I’ve tried to contribute a bit by explaining a simple approach for storing server-side data in JavaScript arrays.

Following this technique, I’ve developed a “createJavaScript()” PHP function, which is fed with server-side data (files or result sets), and returns a JavaScript array populated with these contents. For a full review of this function, please return to part one of this series. While this function is not going to blow your mind away, it has proven to be handy in the development of certain applications that may be suitable for small web projects.

In the second part, we added another toy to our developer’s toolbox by creating a file-based news ticker, simply by manipulating JavaScript arrays. Maybe you’re wondering…so what? There are hundreds of those tiny applications out there, ready for copy-and-paste action! Fine, despite the important concept of code reusability, nothing stops us from using PHP and JavaScript to create our own programs.

Considering this, our next and final step will be using this server-client programming interaction to build a JavaScript-based paging system. I mean <previous> 1, 2, 3, …and so forth. Is such a thing possible? Yes, it is. Let’s put our hands to the hard work and start learning more.

{mospagebreak title=Records wanted! Fetching data from tables}

Despite the fact that we’ve discussed in previous articles the significant limitations of storing database records directly in a client’s machine (specifically in RAM), there are some situations where this approach might be pretty useful. In small intranet environments, where the volume of data is rather limited, with applications running with controlled software and hardware resources, this method may find its place. However, anything else falling outside this category certainly should be considered inefficient.

Having stated this disclaimer, it’s time to look at the JavaScript functions needed to create the paging system. But, wait a minute! In order to paginate records we need to fetch them from a database first, right? So, our first task is to connect to the MySQL server, perform a SELECT query against a database, and populate a JavaScript array with the retrieved data. Let’s do it in a procedural way:

$db=mysql_connect(‘dbhost’,’user’,’password’) or die(‘Error connecting to the server’. mysql_error());

mysql_select_db(‘database’) or die(‘Error selecting database’);

$result=mysql_query(‘SELECT * FROM table’) or die(‘Error performing query’);

Now, if things work out just fine, we’ve hopefully obtained a result set. It’s time to invoke our friendly “createJavaSCript()” function, for transferring the records to a JavaScript array, passing as parameters the result set and the name of the array to be generated. Just like this:

echo createJavaScript($result,’rows’);

It’s that simple. Our records happily reside on the “rows” array, waiting to be processed. Our fetched records are stored in the client, ready to be paginated. Let’s define the JavaScript functions.

{mospagebreak title=Defining data containers: the “createDivs()” function}

Before we start writing the code for the JavaScript functions, it’s necessary to initialize a couple of global variables that we need to use at a later time. First, let’s specify the number of records to be displayed at a time. For our example, we’ll assign a value of 4:

var recsPage=4;

Second, let’s calculate the number of pages needed to show the paginated records:

var numPages=Math.round(rows.length/recsPage);

As you can see, this value is obtained by dividing the total number of elements contained in the “rows” array (rows.length) by the total number of pages. Finally, the result is rounded using the “round” method provided by the JavaScript “Math” object. Okay, our work for the variable setup is now finished. Let’s look at the functions.

To begin with, we’ll only need three core functions. The first function, which I’ve named “createDivs,” takes care of creating two <div> containing elements. The first <div> will be used to contain the proper database record values, while the second will hold the paging links. This sounds pretty logical.

Once we’ve seen the reason to create this function, let’s have a look at its definition:

createDivs=function(){
  // create records containing <div>
  var recsDiv=document.createElement(‘div’);
  recsDiv.id=’records';

  // create paging link containing <div>
  var linksDiv=document.createElement(‘div’);
  linksDiv.id=’paginglinks';

  // insert <div> elements into document structure
  document.body.appendChild(recsDiv);
  document.body.appendChild(linksDiv);
}

As you can see, the function creates the “recsDiv” <div> element in memory and assigns to it a “records” ID attribute, handy for applying a CSS style. This is the element that will contain record data. Here’s the code for the element’s creation and ID assignment:

// create records containing <div>
var recsDiv=document.createElement(‘div’);
recsDiv.id=’records';

Next, in a similar way, a second “linksDiv” is generated, tying a “paginglinks” ID to it, suitable for element styling. Obviously, this element will contain the record paging links:

// create paging link containing <div>
var linksDiv=document.createElement(‘div’);
linksDiv.id=’paginglinks';

Once these containers have been created, they are properly inserted in the Web document tree, as follows:

document.body.appendChild(recsDiv);
document.body.appendChild(linksDiv);

I told you that this function was easy to grasp! With this first function defined, our next task is to set up the second one, which is called “displayRecords.” Not surprisingly, it will show the records in a paginated way. Let’s move on and jump into its source code.

{mospagebreak title=Showing database records: the “displayRecords()” function}

When it comes to displaying database records, we need to define a specific function to perform that task. Before we list the function code, let’s explain how it will behave. Doing so, its logic will be much easier to understand. Take my word for it.

Since the records are already stored in the “rows” JavaScript array, the only assignment for this function is to extract the corresponding elements from it, and then insert their values into paragraph elements. Next, the whole set will be wrapped up by a regular <div> container and appended to the document tree. It’s that simple.

I know that explaining this in words without showing any code is pretty pointless, so here’s the listing for our “displayRecords()” function:

displayRecords=function(page){
  var recsDiv=document.getElementById(‘records’);
  if(!recsDiv){return;}
  var div=document.createElement(‘div’);
  div.id=’records';
  if(!page){page=1;}

  // extract records from rows array
  for(var i=(page-1)*recsPage;i<((page-1)*recsPage)+recsPage;i++){
    if(rows[i]){

      // insert records as paragraph elements
      var p=document.createElement(‘p’);
      p.appendChild(document.createTextNode(rows[i]));
      div.appendChild(p);
    }
  }

  // replace old records node with new records node
  recsDiv.parentNode.replaceChild(div,recsDiv);
}

If the above code seems to be a bit messy, don’t worry. We’ll explain some sections of code.

As I said previously, the function really extracts the records from the “rows” array, using a record pointer called “page,” which is passed as the unique parameter. This pointer is used internally to calculate the position within the array and display the exact number of records. The lines listed below perform that operation:

for(var i=(page-1)*recsPage;i<((page-1)*recsPage)+recsPage;i++){
  if(rows[i]){

    // insert records as paragraph elements
    var p=document.createElement(‘p’);
    p.appendChild(document.createTextNode(rows[i]));
    div.appendChild(p);
  }
}

Notice that we’re putting each record inside <p> elements, and wrapping them with a <div> tag. The only thing left is to insert the complete updated structure into the document. To do so, I’ve opted to replace the existing “records” <div> element with a new one, using the expression:

recsDiv.parentNode.replaceChild(div,recsDiv);

Oops! I think that the code was pretty hard to explain, but it’s worthwhile. Thus, having defined the functions to contain records and paging links, as well as for displaying paginated data, what’s our next step? We need to create the paging links. That’s what we’ll learn to do in the next section.

{mospagebreak title=1 – 2 – 3 Next >> Building the paging links}

In order to create the paging links, required to display paged records, we’ll start by defining another useful JavaScript function called “generateLinks,” which accepts only one incoming parameter: an array pointer that nicely determines our position inside the “rows” array.

Using this pointer, the function is capable of verifying whether it’s possible to generate the usual <previous> and <next> links, along with the regular numbered links. But, doesn’t it sound like we’ve used this parameter before? Yes! The pointer is the same one that we utilized to display the records in our previous “displayRecords()” function. As we’ll see in a moment, the same parameter is used to output both records and paging links. But, I’m getting ahead of myself! Let’s get on with the step-by-step explanation process.

For the sake of not feeling overwhelmed by the apparent complexity of the function, let’s divide it into a few more digestible sections. The first one simply retrieves the <div> element for the paging links, creates a new <div> and assigns an “paginglinks” ID attribute to it, as listed below:

var linksDiv=document.getElementById(‘paginglinks’);
if(!linksDiv){return;}
var div=document.createElement(‘div’);
div.id=’paginglinks';

Why are we doing this? Since we’re keeping this on the client side, with no requests to the server to update page contents, this is the basic way we’re updating our paging links. We get the document node identified as “paginglinks” where the links are placed, update them accordingly, and finally replace the old node with a new one. Simply and straightforward, huh?

The second section of the function checks to see whether it’s feasible to generate a <previous> link, in a way similar to that used in server-side scripts. So, here’s the code to generate our link:

// create previous link
if(page>1){
  var a=document.createElement(‘a’);
  a.href=’#';
  a.id=parseInt(page)-1;
  a.style.fontFamily=’Verdana';
  a.style.fontSize=’11px';
  a.style.fontWeight=’bold';
  a.appendChild(document.createTextNode(‘<<Previous’));
  div.appendChild(a);
  a.onclick=function(){

    // update record list
    displayRecords(this.id);

    // update paging links
    generateLinks(this.id);
  }
}

Okay, that’s not big deal! If you have ever created a server-based paging system, the code is fairly understandable. The function checks to see whether the “page” array pointer is placed at a position other than the first one (page>1). If this is true, then a <previous> link is generated, and receives some regular styles, such as font typefaces, font weight, size and color. Then, the classic <previous> label is inserted inside the link, and finally appended to the “paginglinks” <div> container.

However, there are a few things to consider here. Notice that we’ve assigned an ID to the link:

a.id=parseInt(page)-1;

The reason for doing this should become clear. Whenever the link is clicked, we need to update the list of records and the paging links themselves. To do so, we first make a recursive call to the “generateLinks()” function, passing this ID to it, and finally calling our known displayRecords() function, with the same ID value, as illustrated below:

a.onclick=function(){

  // update record list
  displayRecords(this.id);

  // update paging links
  generateLinks(this.id);
}

If you’re feeling a bit confused, don’t worry. It really works!

Next, we’ll focus our attention on the section aimed at generating the numbered links.

{mospagebreak title=Building paging links: the sequel}

How long has it been since we’ve reviewed the process for creating our paging links? A few seconds ago! Thus, let’s move on to explaining how the numbered links are created.

Having calculated the total number of pages needed to display all of the records, the process is pretty straightforward. We simply create regular <a> elements, styling them with a few CSS properties, and insert them as child elements within the general <div> container. Here’s the code to perform those operations:

// create numbered links
for(var i=1;i<=numPages;i++){
  if(i!=page){

    // create paging links
    div.appendChild(document.createTextNode(‘ ‘));
    var a=document.createElement(‘a’);

    // assign paging links attributes
    a.href=’#';
    a.id=i;
    a.style.fontFamily=’Verdana';
    a.style.fontSize=’11px';
    a.style.fontWeight=’bold';
    a.appendChild(document.createTextNode(i));

    // append link to <div> container
    div.appendChild(a);

    // append blank space
    div.appendChild(document.createTextNode(‘ ‘));

    // assign onclick event handler to paging links
    a.onclick=function(){

    // update records list
    displayRecords(this.id);

    // update paging links
    generateLinks(this.id);
    }
  }
  else{

  // the current element is not linked
  var span=document.createElement(‘span’);
  span.style.fontFamily=’Verdana';
  span.style.fontSize=’11px';
  span.style.fontWeight=’bold';
  span.appendChild(document.createTextNode(i));
  div.appendChild(span);
  }
}

If we take a look at the above listed code, the operation to generate the numbered links is rather easy to follow. As I said, this section builds up the links, dynamically creating regular <a> elements, which are properly styled as usual, and assigns some properties, such as font typefaces, color and so forth.

Notice that within the main counter loop, we’re outputting the current element as plain text, opposite to a regular a link. In this case, a <span> element is generated, applying a simple style, and finally appended to the general container for paging links, like this:

// the current element is not linked
var span=document.createElement(‘span’);
span.style.fontFamily=’Verdana';
span.style.fontSize=’11px';
span.style.fontWeight=’bold';
span.appendChild(document.createTextNode(i));
div.appendChild(span);

However, a more detailed explanation is in order. Having generated the paging links, as we did with the previous functions, each time a link is clicked, we need to update the overall output, that is, the record list in conjunction with the links themselves. So, the lines below perform the output updating process:

a.onclick=function(){

  // update records list
  displayRecords(this.id);

  // update paging links
  generateLinks(this.id);
}

There are a couple of things that need to be revised. What about the <next> link creation? Don’t worry; here’s the code section that takes care of that:

// create next link
if(page<numPages){
  var a=document.createElement(‘a’);
  a.href=’#';
  a.id=parseInt(page)+1;
  a.style.fontFamily=’Verdana';
  a.style.fontSize=’11px';
  a.style.fontWeight=’bold';
  a.appendChild(document.createTextNode(‘Next>>’));
  div.appendChild(a);
  a.onclick=function(){

  // update records list
  displayRecords(this.id);

  // update paging links
  generateLinks(this.id);
  }
}

As you can see, this snippet is very similar to the one used to build up the <previous> link. Here, we check whether the “page” array pointer is less than the total number of pages. If this is true, we create the proper link, this time appending to it the label “Next>>”. Also, the updating process applied to each link must be rigorously performed. This way, when the link is clicked, we fire up in sequence our already familiar functions “displayRecords()” and “generateLinks()”, passing the link ID as the parameter:

a.onclick=function(){

  // update records list
  displayRecords(this.id);

  // update paging links
  generateLinks(this.id);
  }

Once all of the paging links have being generated, all that we need to do is replace the old “paginglinks” <div> with the newly updated node, using the following line:

// replace old links node with new links node
linksDiv.parentNode.replaceChild(div,linksDiv);

I think that’s all there to our “genarateLinks()” function. It’s quite lengthy, but don’t feel intimidated by it. At this level, hopefully we have developed the three core functions to display paged result sets, keeping all of the process within the client area.

Now let’s look at how we can use these functions to generate our JavaScript-based result set.

{mospagebreak title=Building client-based result sets: making PHP and JavaScript interact}

Let’s set up a basic example to test our paging system. To keep things simple, we’ll assume that we have stored some records in a database table, which contains data about several songs, including song ID, song title and song author. Nothing unexpected. Here’s the full example:

<?php

  // include createJavaScript function
  require_once(‘createjavascript.php’);

  // connect to the MYSQL server , select database and perform query
  $db=mysql_connect(‘dbhost’,’user’,’password’) or die(‘Error connecting to the server’. mysql_error());
  mysql_select_db(‘database’) or die(‘Error selecting database’);
  $result=mysql_query(‘SELECT * FROM songs’) or die(‘Error performing query’);

  // pass result set $result to the function and create a “rows” JavaScript array

  // with table records
  echo createJavaScript($result,’rows’);

  // paginate records in the client side
?>
<html>
<head>
<title>Paginating Records with JavaScript</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″ />
<script language=”javascript”>
  var recsPage,page,numPages;

  // set number of records per page
  recsPage=4;

  // calculate number of pages
  numPages=Math.round(rows.length/recsPage);

  // define createDivs function
  createDivs=function(){

    // create records containing <div>
    var recsDiv=document.createElement(‘div’);
    recsDiv.id=’records';

    // create paging link containing <div>
    var linksDiv=document.createElement(‘div’);
    linksDiv.id=’paginglinks';

    // insert <div> elements into document structure
    document.body.appendChild(recsDiv);
    document.body.appendChild(linksDiv);
    }          

    // define displayRecords function
    displayRecords=function(page){
       var recsDiv=document.getElementById(‘records’);
       if(!recsDiv){return;}
       var div=document.createElement(‘div’);
       div.id=’records';
       if(!page){page=1;}

       // extract records from rows array
       for(var i=(page-1)*recsPage;i<((page-1)*recsPage)+recsPage;i++){
         if(rows[i]){

           // insert records as paragraph elements 
           var p=document.createElement(‘p’);
           p.appendChild(document.createTextNode(rows[i]));
           div.appendChild(p);
           }
         }

         // replace old records node with new records node
         recsDiv.parentNode.replaceChild(div,recsDiv);
       }

       // define generateLinks function
       generateLinks=function(page){
         var linksDiv=document.getElementById(‘paginglinks’);
         if(!linksDiv){return;}
         var div=document.createElement(‘div’);
         div.id=’paginglinks';

         // assignn default value to array pointer
         if(!page){page=1;}

         // create previous link
         if(page>1){
           var a=document.createElement(‘a’);
           a.href=’#';
           a.id=parseInt(page)-1;
           a.style.fontFamily=’Verdana';
           a.style.fontSize=’11px';
           a.style.fontWeight=’bold';
           a.appendChild(document.createTextNode(‘<<Previous’));
           div.appendChild(a);
           a.onclick=function(){

             // update record list
             displayRecords(this.id);

             // update paging links
             generateLinks(this.id);
           } 
         }

         // create numbered links
         for(var i=1;i<=numPages;i++){
           if(i!=page){

             // create paging links
             div.appendChild(document.createTextNode(‘ ‘));
             var a=document.createElement(‘a’);

             // assign paging links attributes
             a.href=’#';
             a.id=i;
             a.style.fontFamily=’Verdana';
             a.style.fontSize=’11px';
             a.style.fontWeight=’bold';
             a.appendChild(document.createTextNode(i));

             // append link to <div> container
             div.appendChild(a);

             // append blank space
             div.appendChild(document.createTextNode(‘ ‘));

             // assign onclick event handler to paging links
             a.onclick=function(){

               // update records list
               displayRecords(this.id);

               // update paging links
               generateLinks(this.id);
             }
           } 
           else{

             // the current page is not linked
            var span=document.createElement(‘span’);
            span.style.fontFamily=’Verdana';
            span.style.fontSize=’11px';
            span.style.fontWeight=’bold';
            span.appendChild(document.createTextNode(i));
            div.appendChild(span);
          }
        }

        // create next link
        if(page<numPages){
          var a=document.createElement(‘a’);
          a.href=’#';
          a.id=parseInt(page)+1;
          a.style.fontFamily=’Verdana';
          a.style.fontSize=’11px';
          a.style.fontWeight=’bold';
          a.appendChild(document.createTextNode(‘Next>>’));
          div.appendChild(a);
          a.onclick=function(){

            // update records list
            displayRecords(this.id);

            // update paging links
            generateLinks(this.id);
          }
        }

        // replace old links node with new links node
        linksDiv.parentNode.replaceChild(div,linksDiv);
      }

      // execute functions when page is loaded 
      window.onload=function(){
        if(document.getElementById&&document.createElement){

          // create containing <div> elements
          createDivs();

          // display records
          displayRecords(page);

          // generate paging links
          generateLinks(page);
        }
      }
</script>
<style type=”text/css”>
/*define some styles*/

p {
  font: bold 16px Arial, Helvetica, sans-serif;
  color: #000;
}

#records {
  width: 50%;
  background: #ccf;
  font: normal 12px “Arial”, Helvetica, sans-serif;
  color: #000;
  border: 1px solid #000;
}

#records p {
  margin: 10px;
}
</style>
</head>
<body>
<h1>Records Listing</h1>
</body>
</html>

Wow, that was a lot of code! However, it’s more than enough to show how the paging system works. Keep in mind that the example illustrates a basic structure, and improvements are just around the corner. We might work with different PHP files and then include them when necessary. The JavaScript code should be located in an external file, as well as the CSS styles. Whatever you want to do with the example is merely subject to your personal needs. Here’s the output that I get from the browser, using the given example:

The above screenshot looks like we’re paginating records with some server-side language. However, the paging system is working only with JavaScript arrays. Use the code, create the files and test it in your Web server. It’s something that you have to see for yourself. So, our job is finally done.

Conclusion

That’s all for now. We’re completed the series dealing with the PHP-JavaScript interaction, showing a couple of real-world examples, hopefully demonstrating that utilizing a PHP-JavaScript combination is quite powerful, at least, in controlled environments. Of course, when working on larger projects, server-side based solutions rule all the way. But, this technique has a place in our developer’s toolbox as well. You have the power and the knowledge. Just take advantage of it!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort