Three till Seven

Posts with Tag “Javascript”

27 Feb 08 regular Javascript v. AJAX for dynamic content insertion

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

Recently for work, I’ve had cause to write functionality so that a certain chunk of a form can be inserted again, over and over, by the user. The form involves data about course equivalencies between schools, and the user might need to submit data for multiple courses a student has taken. Hence, the user needs to be able to add extra course sections on the fly, as they’re necessary. Here’s a screenshot to better illustrate what I mean:

I decided to do this with Javascript, but the question was:

  • Should I dynamically generate the extra form fields with Javascript before stuffing them into the DOM,

or

  • Should I have a separate page, containing the form fields written in plain HTML, that I dynamically insert into the form page via an AJAX call?

Contemplating the idea, I decided the best route would be to use AJAX. Here are some guidelines for making such a choice, based on the logic I used:

Are you generating a lot of code?
If you’re going to be generating a lot of code each time, like in my example, the AJAX route makes more sense because you can have a separate page (PHP for me, but you could use a straight HTML page) to write that content in HTML, then use an AJAX call to include that page in your main page. See, if you were to use Javascript for dynamically creating elements (document.createElement() and element.appendChild() are your friends here), you’re going to write a lot more code in Javascript than the straight HTML it takes to create various elements and their attributes. In my case, with Javascript I would be generating li’s, span’s, fieldset’s, input’s, and legend’s, then several of those had the attributes rel and class, not to mention the normal attributes associated with input. It’s simpler to write out the HTML for this in a separate page, rather than have lots of Javascript functions for creating those elements, applying attributes to them, assembling them together, then stuffing the result somewhere in the existing page.
Does the dynamically added code replicate content already in the main page?
In my example, the main form page started out with one course section already showing up. If I were to use straight Javascript DOM manipulation to allow the user to insert extra course sections, I would be replicating the same content in two ways: in the main HTML page, and in the Javascript necessary to generate a new course section. Being a Ruby girl at heart and a big supporter of the DRY principle (Don’t Repeat Yourself), it hurts something deep inside of me to duplicate that much functionality in my application. Well, maybe I’m exaggerating a bit, but I gotta stress this, because such replication leads to harder-to-maintain code. Any time you want to change the teensiest thing, you have two places in which you need to change it: the original HTML, and the Javascript that creates the same chunk of HTML before inserting it into your page. Going the AJAX way here would be best.
Are you adding only a small piece of HTML?
If you want the user to be able to dynamically add a single link or something equally trivial to your existing page, the AJAX route might be overkill. The Javascript necessary to generate one or a couple HTML elements isn’t overly complex or lengthy, and so it makes sense to use Javascript element generation followed by DOM manipulation to add your new content. I think it would be more trouble than it’s worth to have a separate page containing just a link or two, and then use AJAX calls to stuff that snippet page into your main page.
If your dynamic content isn’t complex now, do you foresee it becoming so in the future?
Maybe for the time being, the user only needs to insert a couple of elements into the page at his or her whim, but in the future, you think your application will expand such that large chunks of HTML will need to be added at a time. In this case, you might start off with the AJAX route just for your future convenience (or the convenience of another developer—be considerate of the next guy, right?). It’ll make your page easier to expand in the future, since you won’t have to remove all the Javascript content generation code, create a separate page to hold the content to be dynamically added, then write the AJAX calls to include that content as the user desires.
Are you using a PHP (or similar server-side language) back end?
The site I was creating my example form for uses PHP, so the AJAX route especially makes sense here, since I can make the dynamic addition of content be available for the user even if they have Javascript disabled. I’ll just use PHP to parse a POST request and decide how many course sections to include (using a loop and PHP’s include on the separate snippet page of content), based on how many they currently have and how many extra they want to add. With the Javascript content generation route, this sort of thing is impossible, because Javascript is entirely client-side, and if the user doesn’t have it enabled or their browser doesn’t support it at all, they’re up a creek. Oh sure, you could have the non-AJAX version for those with Javascript, then write functionality in a server-side language to allow the user the same functionality without Javascript enabled, but there you go again with the replication of functionality—bad programmer! If you’re stuck with just HTML, though—which I have to guess is unlikely in this day and age, what with every Tom, Dick, and Harry of hosts supporting PHP, Perl, JSP, and Ruby—you’ll need to determine whether to go AJAX or Javascript-content-generation based on the other questions raised above.

26 Sep 07 using Javascript and CSS to mark outgoing links

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

It may be useful to your visitors to know which links will take them off of your site without having to hover over all of them. It might also be a nice touch to mark links pointing to PDF documents, for example, with a little Adobe PDF logo. With the help of Javascript and CSS, you can do this pretty simply.

First, we need some Javascript to go through our page and add a CSS class to every link that we want to differentiate.

JAVASCRIPT

// Goes through all links in a page and adds CSS
// classes to them to better style outgoing links,
// PDF links, etc.
function link_classifier() {
  // Get an array of all links in the page
  var links = document.getElementsByTagName( 'a' )

  // These variables will be used later to store
  // the current 'a' object we're working with,
  // and its URI
  var curr_link, uri

  // A regular expression to match URI's ending
  // in 'pdf'
  var pdf_regex = new RegExp( 'pdf$', 'i' )

  // A regular expression to match URI's beginning
  // with 'http://', which we will assume go to
  // other sites
  var outside_regex = new RegExp( '^http://', 'i' )
   
  for ( var i=0; i<links.length; i++ ) {
    curr_link = links[i]
    uri = curr_link.getAttribute( 'href' )
       
    // Add a CSS class to PDF links
    if ( pdf_regex.test( uri ) )
      add_class( curr_link, 'pdf' )
       
    // Add a CSS class to outside links
    if ( outside_regex.test( uri ) )
      add_class( curr_link, 'outside' )
  }
}

// Given some object and a class name, this
// function will append the given class name
// to the CSS class of the object
function add_class( object, class_name ) {
  var old_class = object.getAttribute( 'class' )
   
  if ( old_class == '' || old_class == null )
    object.setAttribute( 'class', class_name )
  else
    object.setAttribute( 'class', old_class + ' ' + class_name )
}

// Tell the browser to run our link_classifier
// function when the page loads
window.onload = link_classifier()

Now we can style the links based on their class names. You could do whatever you wanted to with them, maybe make all outgoing links bold, whatever. For me, I like having little icons next to outgoing links or other special links. If it's a PDF document, maybe use an Adobe logo. If it's an MP3, a little music note. Get creative! Anywho, here's some CSS for sticking such little logos in after the text of a link:

CSS

a.outside {
  background: url('outgoing_link.gif') no-repeat right center;
  padding-right: 11px;
}

a.pdf {
  background: url('pdf.gif') no-repeat right center;
  padding-right: 14px;
}

I set the right padding to be the width of the icon plus 1, so that the icon wouldn't be pressed right against the text.

14 May 07 using AJAX to implement a live search

Note: If you enjoy this article, you might also check out the Geeky Stuff section.

I recently implemented a live search on the quotes page, so I figured I'd give a tutorial on how I did it. A "live" search is like a regular search feature, but if the user has Javascript enabled, the search will run as they type, instead of waiting for them to hit the 'Submit' button. There are a couple of advantages to this, one being that it's a bit quicker than a traditional search because it starts working immediately; another advantage is that it might help you narrow down your search better (e.g. you initially want to search for 'frogs', but you get just 'frog' typed in and see results that interest you that wouldn't have seen with a 'frogs' query). However, I think the main benefit from a live search is that it's cool. :)

Things You'll Need

  • PHP for the search backend;
  • The Prototype Javascript framework in order to easily make an AJAX call with the visitor's search query.

Query-parsing Backend

We should get our search working without any fancy AJAX first to know that it works. My quotes are stored in a plain-text file and I use PHP to display them. We want a PHP script that we can pass a query to, either by a GET or a POST request (i.e. through a URL parameter or from a form), and that will then search through our quotes file for the given query. Here's what I came up with, which I named quotes_search.php:

PHP

<?php
// Given a Regular Expression and an array,
// it will return an array of all keys for which
// the regular expression matches the array
// value at that key
function array_regex( $pattern, $haystack ) {
  $keys = array();

  // Go through the given array
  foreach ( $haystack as $i => $value ) {
    // Check to see if the current array value
    // matches the given pattern
    if ( preg_match( $pattern, $value ) )
      // Use array_unshift instead of array_push
      // so that the latest quote keys are added
      // to the beginning of the array and not the
      // end--want to display the quote search
      // results in reverse order
      array_unshift( $keys, $i );
  }

  return $keys;
}

// Get the query either from a GET or POST request
if ( array_key_exists('query', $_GET) )
  $query = $_GET['query'];
else if ( array_key_exists('query', $_POST) )
  $query = $_POST['query'];

// Where the quotes are stored; plain-text file
$data = '/path/to/quotes/file/quotes.txt';

// Turn that quotes file into an array of lines
$file = file( $data );

// If the query was blank...
if ( $query == '' ) {
  // Just display the entire quotes file
  $count = count( $file );
  echo '<ol class="padded">';

  // Display the quotes from the most recent to the earliest
  for ( $i=$count-1; $i>=0; $i-- ) {
    $file[$i] = trim( $file[$i] ); // Get rid of carriage return

    // For odd-numbered indices in the quotes array, put a
    // different CSS class on the li tag so that we can style
    // it differently for readability
    if ( $i % 2 == 0 )
      echo '<li>';
    else
      echo '<li class="alt">';

    // Place an anchor tag where the name attribute is set
    // to the quote's index in the quotes array, so that we
    // can link directly to this quote later if we like
    echo '<a name="' . $i . '"></a>';

    // Display the quote itself
    echo $file[$i];
    echo '</li>';
  }

  echo '</ol>';
} else {
  // Remove any slashes in the query so as not to mess with PHP's
  // RegEx support
  $query = str_replace( '/', '', $query );

  // Find the indices that have matching values to the given query,
  // case insensitive
  $keys = array_regex( "/$query/i", $file );

  // If there were any indices found with matching values...
  if ( count($keys) > 0 ) {
    echo '<ol class="padded">';

    // Go through the indices
    foreach ( $keys as $count => $key ) {
      // For odd-numbered indices in the quotes array, put a
      // different CSS class on the li tag so that we can style
      // it differently for readability
      if ( $count % 2 == 0 )
        echo '<li>';
      else
        echo '<li class="alt">';

      // Display the quote itself
      echo $file[$key] . "</li>\n";
    }

    echo '</ol>';
  } else {
    // No matching quotes were found
    echo '<p>No quotes match your search.</p>';
  }
}
?>

Displaying the Quotes

When no query is submitted, we want to see all the quotes. In my Wordpress Quotes page, I have the following:

HTML

<div id="quotes"><?php include '/path/to/searching/backend/quotes_search.php'; ?></div>

Since we're including the search backend without any query passed to it, the PHP code shown above will just spit out the quotes in a nice ordered list. The div tag with its ID "quotes" is very important, as this will be used later by some Javascript to display the search results.

Making It Live

Now that we have our PHP backend, we can work on the Javascript side of things. We still want people with Javascript disabled to be able to use our search, though, so we set up the HTML form like any other form. We can, however, hide the submit button from those that have Javascript enabled, so as to make it clearer that submitting the form in the usual way is unnecessary. Here's the HTML I used:

HTML

<form action="/wp-content/quotes_search.php" method="post">
<p><input type="text" name="query" size="20" id="query" /></p>
<span id="loading" style="display: none;"><em>Searching quotes...</em></span>
<span id="complete" style="display: none;"><em>Search complete!</em></span>
<script type="text/javascript">
  document.write('<p><em>Hint:</em> It searches as you type.</p>');
</script>
<noscript>
  <p><input type="submit" value="Search" /></p>
</noscript>
</form>

See the span tags that are set to display: none? Those will be used to notify the visitor that a search is taking place or has completed. They start out hidden because nothing initially happens with the search; we'll use Javascript to display them and re-hide them as necessary. In the noscript area, which will be seen by users without Javascript, we include a submit button. For those with Javascript, we offer a helpful hint that no form submission is necessary.

This HTML by itself won't do anything special. What we really need is the Javascript code to check when our search input field (with ID "query" above) has been updated and then initialize a search. Here's that code:

JAVASCRIPT

<script type="text/javascript">
  //<![CDATA[
  new Form.Element.Observer(
    'query',
    0.5,
    function(element, value) {
      new Ajax.Updater(
        'quotes',
        '/url/to/search/backend/quotes_search.php?query=' + value,
        {
          asynchronous:true,
          evalScripts:true,
          onComplete:function(request){Element.hide('loading'); Element.show('complete');},
          onLoading:function(request){Element.hide('complete'); Element.show('loading');}
        },
        {parameters:value}
      )
    }
  )
  //]]>
</script>

That's a hairy chunk of Javascript, I know. What it's doing is creating an Observer (thank you, Prototype) for the element with the ID "query" (which is our search input field). The Observer checks the search field every 500 milliseconds for changes. When changes are detected, it executes the function that is the third parameter. The function contains an Updater, which will update the element with the ID "quotes", which is our div container holding all the quotes in our page. The Updater uses AJAX to send a request to the URL '/url/to/search/backend/quotes_search.php?query=' + value, where value will be replaced with the value Javascript extracts from the search input field. The next Updater parameter is a hash of options, including two for showing and hiding our span tags when a query has completed or is in process. The final Updater parameter defines what parameters we want from the search input field, for use in our backend. You'll want to stick this chunk of Javascript somewhere after your div containing the quotes and the search form, so that all the necessary ID's the Javascript uses will be available to it.

Overall View

To sum up, here's what we've got and what we're doing with it:

  1. We have a plain-text file containing quotations, called quotes.txt;
  2. We have a Wordpress page in which we want to show these quotes, as well as offer a live search so that users can find specific quotes;
  3. We have a PHP backend in quotes_search.php that will search quotes.txt for a given query;
  4. We display the quotes in our Wordpress page and stick in the search form anywhere we please; after both of these items, we stick in the Javascript that will make our AJAX call;
  5. When a user with Javascript enabled types something in the search field, a Javascript Observer sees this and pokes the Javascript Updater;
  6. The Updater then gets off its butt and grabs the value from the search field, then throws it at quotes_search.php via GET request (that is, it passes the query as a URL parameter);
  7. If the user does not have Javascript enabled, they hit the submit button just like in any other form and the query is passed to quotes_search.php via a POST request (that is, it passes the query as a parameter in the form submission);
  8. The PHP backend takes the query and searches all the quotes in quotes.txt for all quotes that match; it then displays matching quotes in an ordered list. If Javascript is enabled, the matching quotes will be displayed inside the "quotes" div; if Javascript is disabled, the quotes will be displayed in a standalone page.

« Older entries