jQuery - inline editing/ add new row with tablesorter plugin

Monday, 19 January 2009

View Comments

In this tutorial I go over some cool things that you can do with jQuery and the tablesorter plugin. In particular inline editing while maintaining sort functionality and being able to add a new row while maintaing the ability to inline edit and sort the new row correctly. After we insert a new row we also want to update our zebra striping.

The tablesorter plugin is easy to implement and handles things such as zebra striping and custom parsers with ease. If you haven't had a chance to use it yet I suggest you look at it here and go through some of the documentation and try it out for yourself.

To view a working example take a look here

I start with a file called sorter.php and an array of animals which is the data I will be displaying in my table:

$animals = array(
0 => array(
'name' => 'Cow',
'age' => '4',
'location' => 'Barnyard'
),


Then I loop through my animals and create the rows for my table as such:

$tablerows = array();

foreach ($animals as $key => $animal) {
$tablerows[] = <<<EOT
<tr class="dataline">
<td class='name'>{$animal['name']}</td>
<td class='age'>{$animal['age']}</td>
<td class='location'>{$animal['location']}</td>
<td><a href="#" class="editlink"><img alt="Edit" style="border: 0px none; margin-left: 5px;" src="images/icons/page_edit.gif"/></a></td>
<td><a href="#" class="removelink"><img alt="Remove" style="border: 0px none; margin-left: 5px;" src="images/icons/bin.gif"/></a></td>
</tr>
<tr class="editline" style="display:none;">
<form>
<td><input type="text" name="editname" value="{$animal['name']}" /></td>
<td><input type="text" name="editage" value="{$animal['age']}" /></td>
<td><input type="text" name="editlocation" value="{$animal['location']}" /></td>
</form>
<td colspan="2">
<a href="#" class="savelink">Save</a> | <a href="#" class="cancellink">Cancel</a>
</td>
</tr>
EOT;
}


You can see for each animal there are two rows with classes dataline and editline. dataline contains the row as it is seen in the table, editline is hidden and is the row that will be displayed during our inline edit. I displayed the css inline to the editline row as placing it in the css file screws up the zebra stiping for some reason, when I have it inline the same zebra striping class is applied to both the dataline and editline rows which is what we need.

Later we will add a click function to the editlink and cancellink links to toggle our data/edit views using jQuery. Clicking on the savelink link will update our row. Note that for this tutorial I am not connecting to a database or using funky AJAX calls; it should be straightforward looking at the code where this should go and is outside the scope of this tutorial (if you would like suggestions on doing this drop me an email). The remove link also currently just links to a call to the remove() function for simplicity purposes.

Lets have a look at the rest of our sorter.php file:

<div id="content">
<p id="updatemessage"></p>
<button id="addrowbutton" name="addrow">Add row</button>
<table id='mySortable' class='tablesorter'>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Location</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<tr id="addrow" style="display:none;"> <!-- Our add new row -->
<form>
<td><input type="text" name="addname" value="" /></td>
<td><input type="text" name="addage" value="" /></td>
<td><input type="text" name="addlocation" value="" /></td>
<td>
<a href="#" id="saveadd">Save</a> | <a href="#" id="canceladd">Cancel</a>
</td>
</form>    
</tr>
</thead>
<tbody>
<?php foreach ($tablerows as $row) { echo $row; } ?>
</tbody>
</table>
</div>


OK, we have our updatemessage where messages will be displayed whenever an item is added, updated or deleted. We also have a button to add a new row.

The next interesting thing to look at is the <thead> section. You can see that it has two tr's. As commented the second tr is for our addrow functionality. We could just clone a row each time we wanted to add a new row and clear out the fields; I think this is the easier way around, it's stuck inside the thead so it doesn't interfere with the sorting.

Later we will add our save functionality to this which will clone the top row from the table and update the fields accordingly.

I'm not going to over everything in our javascript file but if you would like to view the source look here

Here is the call to the tablesorter plugin:

$("#mySortable").tablesorter({
widgets: ['zebra'],
headers: {
0: {
sorter:'inline'
},
1: {
sorter:'inline_number'
},
2: {
sorter:'inline'
},   
3: { 
sorter: false 
}, 
4: {
sorter: false 
} 
}
});


You can see here we have attached our "zebra" widget which will place alternating classes on each line of our table. You will see for each column I have specified a sorter. For the Edit and Delete columns I have specified to remove sorting from them. You can also see for the other columns I have specified custom sorters. The purpose for this is because our rows for inline editing interfere with the natural table sorting.

Here is our inline custom parser:

$.tablesorter.addParser({ 
   id: 'inline', 
   is: function(s) { 
   return false; 
}, 
format: function(s) { 
   var pattern = 'value=(?:\"?)([^"]*)(?:\"?)\\s';
   matches = s.match(pattern);

if (matches != null) {
   jQuery.makeArray(matches);
   result = matches[1];
} else {
   result = s;
}
return result; 
}, 
type: 'text' 
});

This uses a regular expression to see if what is passed in is our edit row with something along the lines of: "<input type="text" value="Cow" name="editname"/>". If that is the case it just grabs what is inside value="" and passes that back to use for sorting, if there is no match it just uses the value.

The rest should be pretty straight forward. The only other special thing to note is the last line of the add new line function $("#saveadd").click(function() {
the call $("#mySortable").trigger("applyWidgets", "zebra"); just says to reapply the zebra striping once the new line has been added.

This should cover what is going on, if you have anything specific you would like expained just leave a comment. Take time to have a look at the source including the javascript file here

Enjoy,
Tim.
more...

jQuery - Multiple draggable elements

Tuesday, 13 January 2009

View Comments

This tutorial outlines how to drag multiple elements with jQuery's draggable.

Update: This post has been updated, please go here to view the updated article.

Currently it is possible to drag individual elements, but I wanted to try and get jQuery to drag multiple elements after selection. I also wanted the handle to be any of the selected elements for convenience.

I did some searching and couldn't find another implementation of this so if you have any ideas on how this could be improved just let me know. To select multiple elements for dragging just ctrl-click and they will highlight green. To un-highlight just ctrl-click again. Elements that have not been highlighted can still be dragged individually.

Other improvements that could be implemented:
* I had a file manager in mind when I implemented the ctrl-click, so it would be nice to have click anywhere besides a highlighted element removes highlighting from all elements

* Single click on any item removes highlighting from other elements and places highlighting on that element

* Shift-click will highlight multiple items according to their index as per file manager


You can view a working demo here.

This relies on jQuery draggable to work.

Our html file for this implementation has a bunch of square divs that can be dragged around together, as such:

<div class='blue draggable'></div>
     <div class='blue draggable'></div>
     <div class='blue draggable'></div>


Here is the css that I've used:

.blue {
     height:40px;
     width:40px;
     border:1px solid blue;
     background-color:aliceBlue;
     display:block;
}

.grouped {
     border:1px solid greenYellow;
     background-color:honeyDew;
}

Our blue class just defines our blue square to be dragged, this can be changed to your taste.

The grouped will be used later as our highlight to indicate which elements are currently grouped together.

The draggable class is used to indicate which elements are draggable using jQuerys draggable. I didn't want the styling to be on all elements that have class draggable in case we want to use that for other elements later on, so I created the blue class to keep the styling separate from the action.

Now let's look at the javascript. As per usual with jQuery we start off with our document ready function.

$(document).ready(function() {
     $(".blue").click(function(event) {
          if (event.ctrlKey) {
               $(this).toggleClass('grouped');
          }
     });

And then comes our click function for our 'blue' elements. It essentially checks to see if our element has been ctrl-clicked and then toggles the grouped css class so we can see which elements will be dragged together.

Next comes our dragging function. We want to specify details inside our call to draggable as such:

$(".draggable").draggable({
     start: function(event, ui) {
          posTopArray = [];
          posLeftArray = [];
          if ($(this).hasClass("grouped")) {  // Loop through each element and store beginning start and left positions
               $(".grouped").each(function(i) {
                    thiscsstop = $(this).css('top');
                    if (thiscsstop == 'auto') thiscsstop = 0; // For IE

                    thiscssleft = $(this).css('left');
                    if (thiscssleft == 'auto') thiscssleft = 0; // For IE

                    posTopArray[i] = parseInt(thiscsstop);
                    posLeftArray[i] = parseInt(thiscssleft);
               });
          }

          begintop = $(this).offset().top; // Dragged element top position
          beginleft = $(this).offset().left; // Dragged element left position
     },
     drag: function(event, ui) {
          var topdiff = $(this).offset().top - begintop;  // Current distance dragged element has traveled vertically
          var leftdiff = $(this).offset().left - beginleft; // Current distance dragged element has traveled horizontally

          if ($(this).hasClass("grouped")) {
               $(".grouped").each(function(i) {
                    $(this).css('top', posTopArray[i] + topdiff); // Move element veritically - current css top + distance dragged element has travelled vertically
                    $(this).css('left', posLeftArray[i] + leftdiff); // Move element horizontally - current css left + distance dragged element has travelled horizontally
               });
          }
     }
});

Now lets run through what is there...

We start off by calling draggable on all the elements that have the ".draggable" css class.

Then we have two special variables inside our draggable call start: and drag:.

Start is called at the time we start dragging our element and drag is called as the element is being dragged.

Inside the start function we loop through all the elements that have the class grouped. We then store the starting top and left (vertical and horizontal) positions of each element in the posTopArray and posLeftArray variables. We also store the starting top and left position of our parent element being dragged in begintop and beginleft vars.

As the parent element is dragged we calculate the distance it has moved between begintop and beginleft and where it currently is and we store this difference in the topdiff and leftdiff vars.

We then loop through each of the grouped elements and move them the same amount of distance, which is the starting position of the element stored in postTopArray and posLeftArray and add on the values of topdiff and leftdiff.

This has been tested in Firefox and IE 6/7.
more...

php tutorial - separate your application logic from your presentation logic

Friday, 9 January 2009

View Comments

There are many good reasons to separate your programs logic from the presentation code; readability, reusability and the ability to make changes in one part without having to make changes to the other half.

Recently there has been a lot of talk (and adoption) of MVC frameworks (heck even MS has a framework for .net now). With some of the top php programmers helping to build these frameworks there are a lot of good lessons we can learn, especially when it comes to separating our logic from the presentation code, one of the main aims of MVC. Of course you can just grap one of these and not have to worry about reinventing the wheel, but there are a few good reasons that you would want to know how to do this:

1. The size of your project doesn't warrant having an entire framework built in to your site / app
2. You are just starting to learn about MVC concepts and you want to learn more
3. You want to be able to build it in a way that is useful and familiar for reuse in your own apps

Note: That in order for this to work you will need to have a web server with some form of mod-rewrite with htaccess support available.

This is the basic outline of what happens:

Our URL: mysite.com/fishing/home

request is made -> htaccess redirects to a base file (e.g. index.php) -> index.php interperates request variables and redirects to appropriate file for processing (e.g. -> fishing.php) -> our processing script reads in the appropriate template (html file) and replaces 'place holders' in the template with our processed content -> script echos out the file with all content

This might sound a little confusing at first but we can break it down with an example.

We start with our web server with htaccess available.

The files we need are as follows:

/.htaccess
/index.php
/controllers/fishing.php
/views/fishing/home.html

Please note the structure, it is important that we have a good structure of where to place our files. A good structure helps us to locate files, rather than having everything in the same folder. Because we may have two similar requests e.g. mysite.com/fishing/home and mysite.com/diving/home we need to have another tier in our views folder i.e.

/views/fishing/home.html
/views/diving/home.html

So from another perspective the flow works as thus: .htaccess -> index.php -> /controllers/fishing.php (reads in ->) /views/fishing/home.html

Looking at our URL we can see this is directly related

mysite.com/fishing/home ===> (site)/(controller)/(view)

So we now have our application logic in the controller and the presentation in the view and this is directly related to the request made by the user... neat!

So lets have a closer look at each of the files and see how this all comes together.

Firstly our .htaccess. We want to forward the request on to index.php and grab the extra parts of the request, the /fishing/home part of the URL.

Here is what the .htaccess file looks like:

RewriteEngine On // Turn rewrite engine on
RewriteCond %{REQUEST_FILENAME} !-d // If the request is for a real directory go to that directory
RewriteCond %{REQUEST_FILENAME} !-f // If the request is for a real file go to that file
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] // This is where the magic happens, it grabs our /fishing/home, redirects us to index.php and then appends the /fishing/home as follows: index.php?url=/fishing/home
// In regards to the QSA I think this forum entry explains it best.
// L tells the rewrite engine not to apply any more rules

So we now have the first step in place, we get our url stored in the $_GET['url'] variable and we have been redirected to index.php by our htaccess file.

The next step is our index.php. We want to inerpret what is stored in $_GET['url'] and redirect to the correct controller. This is only a simple example but you should make sure when you implement that you check that what comes in through $_GET is clean and you should always make sure someone can't compromise your system just by typing in a url i.e. mysite.com/fishing/delete_everything

You should also make sure you have error handling in your application for when someone specifies an incorrect controller/view or doesn't specify one or the other.

Let's have a look at our index.php:


<?php

$url = $_GET['url']; // Remember to clean this is a real-world situation
$parts = split('/', $url); // Going to store parts of our request url in $parts

$controller = $parts[0]; // In our case fishing.php

// Insert URL checking here to see if view / controller exists

$controllerloc = DOCROOT . 'controllers\' . $controller . '.php'; // Set up a link to the controller location

include($controllerloc); // Include our controller

?>


There are much better ways to implement this, but this should give you a good overview of what should happen. In most good apps the controller will be an object, allowing for better handling etc.

Now lets take a look at fishing.php in the controllers folder. We want this folder to load our template, do some manipulation and then display our page.

// Firstly we want to get our view from the url
$url = $_GET['url']; // Remember to clean this is a real-world situation
$parts = split('/', $url); // Going to store parts of our request url in $parts

$view = $parts[1];
$vars = $parts[2]; // In case any extra variables are passed through e.g. mysite.com/fishing/edit/54

Now that we have our view we can call that method from within the controller, as previously mentioned the controller should be an object with all of the 'views' as methods. I am doing it as functions for simplicity sake.



<?php

// Firstly we want to get our view from the url
$url = $_GET['url']; // Remember to clean this is a real-world situation
$parts = split('/', $url); // Going to store parts of our request url in $parts

$view = $parts[1];
$vars = $parts[2]; // In case any extra variables are passed through e.g. mysite.com/fishing/edit/54

// Check function exists
if (function_exists($view)) {
call_user_func($view);
}


function home() {
$viewloc = DOCROOT . 'views\fishing\home.html';

// Check view exists

$viewHTML = file_get_contents($viewloc);

// *** do some processing ***

echo $viewHTML;
}

function add() {

}

function check() {

}

// etc. etc. ... other functions


?>



So you can see that we grab the view, do some procesing and then echo our our HTML. So what is going on inside the 'do some processing part'?

This is where the application logic goes in, you may read some information from the database, trigger another process and then prepare other information ready for display. So how do we get this information in to our HTML in the correct place without have the two mashed together? There are a few points of information:

1. You will often need your controller to generate some HTML code, this is fine just as long as it's not generating the whole header or whole sections of HTML code.
2. You will often need to perform some manipulation of the information that comes from the controller inside the view. That is also fine. The way this is normally done is rather than getting the view using file_get_contents, we simply include the view file and have some small php calls e.g. looping over data results inside there.
3. To get your code from the controller into the view, the nicest way to do this is by using placeholders inside your view file and using str_replace to replace your place holders with the code.

How to use place holders and str_replace:

You can decide how your placeholders will look like i.e [-how_happy_am_i-] Once you have read your file in using file_get_contents you have your information stored in a variable as follows:


$viewHTML = file_get_contents($viewloc);
$mymood = 'damn happy';


Then to replace the place holder with your mood you simply call str_replace as such:


str_replace('[-how_happy_am_i-]', $mymood, $viewHTML);


There we go, easy as pie. Then we can have our calculate variables injected into our HTML code without having to have all that logic stuck inside... sweet!

Of course if you are going to use place holders, it's always good to have a function to clear out any remaining placeholders in the code before echoing to the screen in case you leave them behind.


Many places are now adopting frameworks and code separation as it has many benefits and it is a huge plus for readability and later updates. It's a good tool to have in your belt and many job advertisiments are asking for people with understanding of MVC.
more...

jQuery - toggle more / less text

Wednesday, 7 January 2009

View Comments

This next tutorial is a nice easy implementation of a more / less toggle on a paragraph with text. This can be used in a variety of ways with a few simple changes e.g. expanding a div.

We will have a paragraph with some text in it and a more/less link down the bottom that will change depending on the current state. Basically when there is less text it will say 'more' and when there is more text it will say 'less'.

It's pretty straight forward but quite useful.

This has been tested in Firefox and IE. Be aware the chosen height of my text paragraph will cut-off the text in the middle depending on the browser so will need a bit of fiddling with css when implementing.

Start off with our text paragraph in its 'less' state with the 'more' link showing:


<p id="mytext" style="'width:260px;height:200px;overflow:hidden;'">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque iaculis tincidunt tortor. Nulla turpis dui, gravida non,
varius quis, molestie sit amet, justo. Vestibulum sed elit.
Duis lobortis odio quis nisi. Praesent enim. Sed auctor commodo lectus.
In eget augue a nulla auctor interdum.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
Nulla enim turpis, commodo at, feugiat nec, dapibus et, odio. Cras enim risus, sagittis eget,
ultrices quis, eleifend vel, risus. Cras a felis eu urna ornare vulputate.
Pellentesque viverra, lacus vitae tincidunt accumsan, nisi metus feugiat felis,
sed placerat est dolor et eros. Duis cursus. Maecenas sollicitudin, lorem vitae
placerat eleifend, dui elit imperdiet tellus, at convallis sapien orci sed pede.</p>
<a href="#" id="adjust">more</a>


Next we place our toggle function inside our javascript file as such:


$(document).ready(function() {
var adjustheight = 200;
$("#adjust").toggle(function() {
$('#mytext').css('height', 'auto').css('overflow', 'visible');
$(this).text("less");
}, function() {
$('#mytext').css('height', adjustheight).css('overflow', 'hidden');
$(this).text("more");
});
});


Nice, straight-forward and effective.

P.S If you are looking for a lorem ipsum generator, this is a good one here.
more...

jQuery - toggle link color and paragraph text

Tuesday, 6 January 2009

View Comments

This is a brief tutorial on how to switch link highlight color and display the corresponding text to the selected link using JQuery.

I have cut things down to the simplest possible stylings and content, but it can be used in many different situations.

The basic idea is having a row of links i.e. Link 1 | Link 2 | Link 3 etc. and a corresponding paragraph of text i.e. Paragraph 1, Paragraph 2 etc.

We want to be able to set which paragraph is selected initially and have the correct link highlighted and have the other paragraphs hidden and links marked in a 'passive' unselected color.

When a new link is selected the new paragraph text is displayed and the correct highlight applied to the currently clicked link.

To do this we need to have a copy of jQuery downloaded into your javascript folder. We will also create two other files; toggle.html in the root folder and toggle.js in our javascript folder.

Our toggle.html file is simple enough; it has a bunch of links and a bunch of text as follows:
<a class="links" href="#">Text 1</a>
<a class="links" href="#">Text 2</a>
<a class="links" href="#">Text 3</a>
<a class="links" href="#">Text 4</a>
<a class="links" href="#">Text 5</a>
<a class="links" href="#">Text 6</a>
<p class="paras">This is my 1 text</p>
<p class="paras">This is my 2 text</p>
<p class="paras">This is my 3 text</p>
<p class="paras">This is my 4 text</p>
<p class="paras">This is my 5 text</p>
<p class="paras">This is my 6 text</p>
Don't forget the reference to the jQuery and toggle.js files in the head.

Now inside the toggle.js we want to set up our document ready function:

Firstly set up three vars; the 'active color' for our active link, the 'passive color' for non-active links and then set up a variable for which paragraph will be selected as default.


$(document).ready(function() {
var activecolor = 'green';
var passivecolor = 'grey';
var activetext = 0;


Next we'll set all the current links to the passive color and hide all the text:


$(".links").css('color', passivecolor);
$(".paras").css('display', 'none');


We then set the active link based upon our activetext variable. We do this using jQuery's eq function

$(".links:eq(" + activetext + ")").css('color', activecolor);
$(".paras:eq(" + activetext + ")").show();
We then finish off by setting the click function for all the other passive links. We do this by first setting all the links to passive, hiding all the paragraphs and then setting the selected text and link to active, similar to what is done initially.

$(".links").click(function() {
// Set all current links to passive and hide all text
$(".links").css('color', passivecolor);
$(".paras").css('display', 'none');
$(this).css('color', activecolor);
var selectedpos = $(this).prevAll(".links").length;
$(".paras:eq(" + selectedpos + ")").show();
return false;
});
Take note of the ".links" when calling prevAll this is in case there are other child elements similar as $(this) which may result in getting the wrong index, using ".links" narrows down the child elements to this with the links class.
more...