Simple Draggable Element Persistence with jQuery width=

Simple Draggable Element Persistence with jQuery

Oct 29th in JavaScript & AJAX by Dustin Blake

At some point you may need to create a draggable element within your web application. This is great functionality, however you may want or find that you need the element to stay in place after being dragged around. In this tutorial I will show you how to easily drag an element and make it stick, even after a page reload, by grabbing and storing its X and Y coordinates.

PG

Author: Dustin Blake

Dustin is a freelance designer/developer and security enthusiast located in the US. In 2008 he was acknowledged for his contribution in the published title "No Root For You" a book with spoon fed security tutorials by Gordon L. Johnson. Dustin can be found at his website http://www.circuitbomb.com.

Scenario

So you have an element in your web application. You can drag it around, put it here and put it there. But, when the page is reloaded in any way, the element returns to its default position. While you want the element to be draggable, you don't want it to move after its been dragged. Let's look at a simple solution to give us this ability.

Getting Started

For this tutorial we are going to need the jQuery library, jQuery UI, and the jQuery-JSON plugin by Brantley Harris. We will also be using some PHP and a MySQL database to parse and store our data. If your new to jQuery, no worries. jQuery is a highly extensible, fast, and lightweight JavaScript library which is both fun and easy to use. The library has very nicely structured documentation, and a huge community. This is my first tutorial on jQuery and JavaScript, so please bear with me. I hope to explain everything as best as I can and if you have any questions, please feel free to ask.

The HTML amd CSS

I wanted to start off with the HTML and styling for this tutorial since the effect is applyed to HTML elements, it helps to visualize what we are going to do, right off the bat. First the CSS:

html, body {
	background:#151515;
	margin:0 0 0 0;
	padding:0 0 0 0;
}

#glassbox {
	background:#333;
	border:1px solid #000;
	height:400px;
	margin:30px auto auto auto;
	position:relative;
	width:960px;
	-moz-border-radius: 10px;
	-webkit-border-radius: 10px;	
}

#element {
	background:#666;
	border:1px #000 solid;
	cursor:move;
	height:143px;
	padding:10px 10px 10px 10px;
	width:202px;
	-moz-border-radius: 10px;
	-webkit-border-radius: 10px;
}

#respond{
	color:#fff;
	margin:0 auto 0 auto;
	width:960px;	
}

The CSS is very simple. We set the html and body properties to clear margins and padding, and continue by setting some heights, widths, and other properties to our elements so it doesn't look so bland. -moz-border-radius and -webkit-border-radius are two properties which allow us to create rounded borders (applicable only to Mozilla Firefox and Safari 3 at the moment) for our elements. Let's take a look at the HTML:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Simple Draggable Element Persistence with jQuery</title>

<link rel="stylesheet" href="style.css" type="text/css" />
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript" src="js/jquery.json-2.2.min.js"></script>

</head>

<body>

	<div id="glassbox">
		<div id="element"><img src="nettuts.jpg" alt="Nettuts+" />Move the Box<p></p></div>
	</div>

	<div id="respond"></div>

As you can see we just setup a very nice and simple page which calls in our CSS, JavaScript library and plugins, and contains the elements which we will be using to apply some effects and events to. As a note,the jquery-ui file is a custom build which only includes the core and the draggable interaction functionality.

The Javascript

Now for some juicy interaction! Lets first take a look at some of the basic functions we will be using to apply some effects to our elements. Let's tear it down.

<script type="text/javascript">
	$(document).ready(function() {
		$("#element").draggable({ 
				containment: '#glassbox', 
				scroll: false
		 })

First we tell the browser, "Hey, this is some code we want to run; it's not HTML, it's JavaScript." We then want to wait for the document to load before we do anything else, once thats happened, we call a function to select our #element DIV, and add the draggable handler with some basic options. The containment options will keep our element within the parent DIV, and we set scroll to false because we don't want any scrolling to happen. Let's move on:

	.mousemove(function(){
		var coord = $(this).position();
		$("p:last").text( "left: " + coord.left + ", top: " + coord.top );
	})

With this tidbit, we call the event handler mousemove and tell it, "When the mouse moves, set the variable 'coord' to equal our selected #element's position." Then we select a paragraph ("p:last"), the last one in #element, and print some text which will read out the left(x) and the top(y) properties of our element relative to the parent object (which is #glassbox).

	.mouseup(function(){ 
				var coords=[];
				var coord = $(this).position();
				var item={ coordTop:  coord.left, coordLeft: coord.top  };
			   	coords.push(item);
				var order = { coords: coords };
				$.post('updatecoords.php', 'data='+$.toJSON(order), function(response){
						if(response=="success")
							$("#respond").html('<div class="success">X and Y Coordinates Saved!</div>').hide().fadeIn(1000);
							setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);
						});	
				});
						
	});
</script>

Ok now for some devilry! In this snippet we are going to do a couple of things. First we want to setup an empty array, and then get some values to fill it with. By calling the event handler .mouseup() we are telling the browser to look for the event when you unclick your mouse. We set the variable coords to equal our empty array, and again set the variable coord to equal the position handler of our #element. Then we need to create a list of items, these will be coordTop: and coordLeft: respectfully equaling our #element's left and top positions. With coords.push(item) we are literally pushing our item list and filling the coords array with it. Then set the variable order as a new list where the coords key will equal our coords array. Now for some AJAX.

$.post is an AJAX request handler which loads a remote page using an HTTP POST method. This function looks for the parameters: url, data, callback and data type to be returned. In this tutorial we specify the updatecoords.php file as our URL because this is where we want to send our post data, we then define our datatype by including the $.toJSON function defined in our jquery-JSON plugin and setting our variable order as the data to be handled by .toJSON. Next we create a callback which checks for a return response from our PHP file upon success, and add a bit of flavor by saying, "If whats returned is equal to success then..." We keep this html hidden by using the effect handler .hide, and tell it to fade in at 1000 milliseconds, wait with a timeout for 2000 milliseconds, and tell it to fade out again. In the end our JavaScript should look like this:

<script type="text/javascript">
	$(document).ready(function() {
		$("#element").draggable({ 
				containment: '#glassbox', 
				scroll: false
		 }).mousemove(function(){
				var coord = $(this).position();
				$("p:last").text( "left: " + coord.left + ", top: " + coord.top );
		 }).mouseup(function(){ 
				var coords=[];
				var coord = $(this).position();
				var item={ coordTop:  coord.left, coordLeft: coord.top  };
			   	coords.push(item);
				var order = { coords: coords };
				$.post('updatecoords.php', 'data='+$.toJSON(order), function(response){
						if(response=="success")
							$("#respond").html('<div class="success">X and Y Coordinates Saved!</div>').hide().fadeIn(1000);
							setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);
						});	
				});
						
		});
</script>

Place the JavaScript below the HTML, right after the closing body tag.

The PHP

Alright, now lets get to business on doing something with the data being posted from our jQuery. First lets create a simple database to store our coordinates, which we will then later retrieve to define the position of our element. Second will be our config.php file which will store our database connection settings, and then we will finish with updatecords.php.

Database: 'xycoords'

CREATE TABLE IF NOT EXISTS `coords` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `x_pos` int(4) NOT NULL,
  `y_pos` int(4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

config.php

<?php
/*Database Settings*/

$db_host ="localhost"; //this will likely stay the same
$db_name = "xycoords"; //name of the database we will be using
$db_usr = "database_username"; //db username
$db_pass = "database_password"; //db password

//Connect to the database
$link = mysqli_connect($db_host, $db_usr, $db_pass) or die("MySQL Error: " . mysqli_error());
//Select our database
mysqli_select_db($link, $db_name) or die("MySQL Error: " . mysqli_error());
?>

updatecoords.php

<?php
if(!$_POST["data"]){
	echo "Nothing Sent";
	exit;
}

include ('config.php');

//decode JSON data received from AJAX POST request
$data = json_decode($_POST["data"]);

foreach($data->coords as $item) {
	//Extract X number for panel
	$coord_X = preg_replace('/[^\d\s]/', '', $item->coordTop);
	//Extract Y number for panel
	$coord_Y = preg_replace('/[^\d\s]/', '', $item->coordLeft);
	//escape our values - as good practice
	$x_coord = mysqli_real_escape_string($link, $coord_X);
	$y_coord = mysqli_real_escape_string($link, $coord_Y);
	
	//Setup our Query
	$sql = "UPDATE coords SET x_pos = '$x_coord', y_pos = '$y_coord'";
	
	//Execute our Query
	mysqli_query($link, $sql) or die("Error updating Coords :".mysqli_error());	
}

//Return Success
echo "success";

?>

This is pretty simple to follow. The first thing we want to do is check to make sure our post data is being passed to the file. If that happens we include our config file for our database connection and set the variable $data to json_decode(passed post variable); json_decode is a PHP function implemented in PHP 5.2.0 which allows us to decode a JSON string.

Since our $data variable contains an array of data, we need to tear it apart to get the values we need. To do this we take foreach $data->coords (which is from our order variable in our JavaScript) as an item. This takes each key and value pair and creates an item object from the array, we then specify and create a variable out of it. We use this in conjunction with preg_replace so that we can take out the characters we don't need. We then, as good practice and a measure of security, escape our values to prepare them for insertion into the database. If all goes well, we need to return success to our JavaScript to let it know everything went just fine.

Lastly

Now that we have what we need in place, to grab the position coordinates from our element and pass it to PHP for storing, we need to modify our HTML to reflect the position of our element. To do this we change the basic element HTML and instead create it with PHP:

<div id="glassbox">
<?php
		//Create a query to fetch our values from the database 	
		$get_coords = mysqli_query($link, "SELECT * FROM coords");
		//We then set variables from the * array that is fetched from the database
        while($row = mysqli_fetch_array($get_coords)) {
			$x = $row['x_pos'];
			$y = $row['y_pos'];
			//then echo our div element with CSS properties to set the left(x) and top(y) values of the element
			echo '<div id="element" style="left:'.$x.'px; top:'.$y.'px;"><img src="nettuts.jpg" alt="Nettuts+" />Move the Box<p></p></div>';
		}			
?>
</div>
<div id="respond"></div>

Here we setup a basic query to the database to select all the rows from the table coords. We then invoke a while loop which specifies each row we select as $row. Now we can set some variables to equal each individual row we pull from the database, and echo them in the proper place within the elements style (left and top).

Wrapping up

Well I hope that you enjoyed this tutorial as much as I did writing it! It may not be perfect. While this is just one way to get this functionality in a draggable element, there are other ways (and perhaps better) to achieve it. Once such way could be to store the coordinate values in a cookie, to keep calls to the database at a minimum. You could also serialize the values passed from jQuery to PHP instead of using JSON. This tutorial is just one example from which you can expand upon. Thanks for reading!


Related Posts

Check out some more great tutorials and articles that you might like

Enjoy this Post?

Your vote will help us grow this site and provide even more awesomeness

Plus Members

Source Files, Bonus Tutorials and
More for $9 a month for all TUTS+
sites in one subscription.

Join Now

User Comments

( ADD YOURS )
  1. PG

    Huckleberry October 29th

    Wow, 1st one to get to comment.
    This looks like just the thing I’ve been looking for!
    Thanks for a great tut!

    ( Reply )
    1. PG

      Paul du Long October 29th

      omf when does this stupid “look how cool i’am because i’am first” thing stops

      ( Reply )
      1. PG

        BroOf October 29th

        Never ever! Now I am the third!

      2. PG

        josh October 29th

        oh mate. its rediculous.

      3. PG

        Flame Boy October 29th

        Fifth, Yes!

      4. PG

        Your Name October 30th

        Sixth, Yes!
        There are a few bugs in this tutorial and could be made much better if it was coded well :( .

  2. PG

    Martin Leblanc October 29th

    Cool tut.

    ( Reply )
  3. PG

    Diego October 29th

    Demo :P

    ( Reply )
    1. PG

      Daniel Groves October 29th

      I agree, a Demo would be nice.

      ( Reply )
      1. PG

        Jason October 29th

        Although, if they had a demo, it wouldn’t be the same if you changed it, someone else visited the page and changed it, and you refreshed.

      2. PG

        Cory Mathews October 29th

        Just remove the mysql part from the demo and have it start at a default position every time.

      3. PG

        BroOf October 29th

        This isn’t very intelligent xD Think about it!

      4. PG

        Dustin October 29th

        @Jason – Right , you would need it to be used in a ‘per person’ form such as in a user table, or in a cookie to ensure the element position is unique to each individual.

      5. PG

        yinyang October 30th

        I agree with Cory.
        When you drag the element around you can show the JSON sent to the server in an alert box.

    2. PG

      Marcelo October 30th

      Demo -> http://www.onlinefacil.com.br/arrastar/savestate.php

      I also made some improvements to work with multiple elements, as it makes sense to have a table for a single record.

      ( Reply )
      1. PG

        Patrick November 1st

        Marcelo, theres a “bug”. If you hold one of the elements and move it to one side of the parent element, hold the draged element and move the mousepointer out of the parent element, the position of the draged element wouldn’t be saved.

        This should be fixed.

    3. PG

      Metin Ucar October 30th

      need demo!!!

      ( Reply )
  4. PG

    Jhon October 29th

    Very cool and become handy

    ( Reply )
  5. PG

    Hamza Oza October 29th

    Nice tut. Enjoyed reading it.

    ( Reply )
  6. PG

    Ryan October 29th

    in the mouseup function, I think you meant to say:

    var item={ coordTop: coord.top, coordLeft: coord.left };

    not:

    var item={ coordTop: coord.left, coordLeft: coord.top };

    ( Reply )
  7. PG

    Ethan October 29th

    Very slick. Will definitely use this.

    ( Reply )
  8. PG

    Zoran October 29th

    Thank you very much for this Dustin, it is very helpful, i wonder if i could apply this to my CodeIgniter project, i am building small CMS HTML editor for my company, but didn’t have any idea how to position some elements in parts of the website. If i had 3 parts website with header, main and footer and in the header div i have logo image, could i use this method to position the logo in the header section and write its new position to the database, so when i produce the layout i will read it from the database. I know it is kind of lame to do such thing, but company wants it and i want to do it :) .
    Thanks again

    ( Reply )
  9. PG

    Asmodiel October 29th

    Hey there!
    Nice tut. But think about that:
    User X moves it around, it gets saved in the DB.
    In this moment user Y reloads the box and the div is on a completely different position!

    Either you should go with … well saving it to the DB along with the IP or you’d have to go with Cookies which in my opinion would be the better oppinion. Like a cookie for a year or so…

    ( Reply )
  10. PG

    Steve Davis October 29th

    Lots of work for something that’s supposed to be “simple”. But still cool :)

    ( Reply )
  11. PG

    Stefan October 29th

    Was surprised to see PHP and mySQL… Isn’t this supposed to be the kind of thing you store in a cookie?

    Whether it’s in a cookie or server side definitely depends on the situation you’re using it for.

    But still, my mental statistics tell me most draggable stuff needs to be in cookies. I’m thinking draggable interface elements (menus, modal windows or option boxes). Those would have no place anywhere else than on the client side.

    Hmm… if you had a puzzle game for maybe with draggable pieces, now that would need to go on the server.

    ( Reply )
    1. PG

      Stefan October 29th

      Uh. Or that game where you have play dress up with a doll.

      ( Reply )
      1. PG

        Ben October 29th

        Should go in a cookie 90%+ of cases.

    2. PG

      Dustin October 29th

      From the last section ‘Wrapping up’:

      “While this is just one way to get this functionality in a draggable element, there are other ways (and perhaps better) to achieve it. Once such way could be to store the coordinate values in a cookie”

      ( Reply )
      1. PG

        Stefan October 29th

        Right, you do mention that!

        I read all the comments before posting mine to see if anyone else said the same thing, but I skipped the end of the article :D

        My bad.

  12. PG

    Roger Roelofs October 29th

    Another option would be to store the coordinates in a cookie instead of the db. It totally depends on why you want the user to be able to drag stuff around. Also, it would be better to use the draggable events rather than mousemove/mouseup. Doing that could simplify your event processing. Good first article.

    ( Reply )
    1. PG

      Dustin October 29th

      Right,cookies are another good option, and may suite many more needs. You have to consider how much persistence you want. Cookies are only as persistent as the user allows them to live or what their time to live is set to.

      ( Reply )
  13. PG

    Hongpak October 29th

    Woow. It Cool!

    ( Reply )
  14. PG

    Anand Kumar October 29th

    I tried it by the source given . there is some bug in the source it is only dragging but not saving the position in the database table ..

    Help me out ..

    ( Reply )
    1. PG

      Dustin October 29th

      That doesnt help solve your problem, could you please be more specific?

      ( Reply )
      1. PG

        Anand Kumar October 29th

        yes i solved
        actually need to stip the slashes in the post request
        chenged the line to from the file updatecoords.php

        $data = json_decode($_POST['data']);

        $data = json_decode(stripcslashes($_POST['data']));

        Now it works fine

        :)

  15. PG

    Jeff October 29th

    How would I make it so I have multiple draggable divs?

    ( Reply )
  16. PG

    Dharmveer Motyar October 29th

    Hi really a nice tutorial..
    but i think there is no need to convert data in json.
    i am sending like this-

    $.post(’updatecoords.php’, ‘data=’+coord.left+’||’+coord.top, function…

    and at updatecoords.php simply –

    $cords = explode(’||’,$_POST["data"]);
    $sql = “UPDATE coords SET x_pos = ‘”.$cords[0].”‘, y_pos = ‘”.$cords[1].”‘”;
    //Execute Query
    mysql_query($sql,$link) or die(”Error updating Coords :”.mysql_error());

    echo “success”;

    ( Reply )
  17. PG

    Monie October 30th

    Where is the demo????

    ( Reply )
  18. PG

    Ted October 30th

    This is really cool! May use this for a flow chart editor I need. Or would you know of any JQuery extension that does flow charting out of the box?
    Thanks for your contribution!

    ( Reply )
  19. PG

    D3rson October 30th

    ok.. nice tut,

    but where is the Demo???

    ( Reply )
  20. PG

    Mohamed Amine October 30th

    Brilliant tutorial. Can be implemented with several projects ideas.

    ( Reply )
  21. PG

    Russ Back October 30th

    Nice tutorial. Makes me think about how browser storage in the more recent versions of Safari et al could pull this kind of personalisation out into the user’s environment and off the server.

    ( Reply )
  22. PG

    esranull October 30th

    very nice but whree is the demo?

    ( Reply )
  23. PG

    z.Yleo77 October 30th

    a powerful code that inspire me something

    ( Reply )
  24. PG

    Big J October 30th

    Can someone explain to me why the use of the json plugin… I’m new to jquery but arent’ you allowed to pass json variables in with your .post anyways?? eg $.post(’updatecoords.php’, {cordx : cordx, cordy : cordy }…

    Dusin or someone else please explain… Thanks

    ( Reply )
  25. PG

    Hello October 30th

    How am I suppose to run this, I mean, it says $_POST but what the hell am I posting???

    ( Reply )
  26. PG

    WebHostDesignPost October 30th

    Nice, cool article – I”m with esranull and Monie -> wheres the demo?

    ( Reply )
  27. PG

    Ismail October 30th

    If it does not work replace

    $data = json_decode($_POST['data']);

    with

    $data = json_decode(stripcslashes($_POST['data']));

    as Anand Kumar pointed out

    ( Reply )
  28. PG

    spido October 30th

    Very nice tutorial!

    @Marcelo: thank you for your demo, great job!
    ( Demo -> http://www.onlinefacil.com.br/arrastar/savestate.php )

    ( Reply )
  29. PG

    Kalvster October 30th

    Good tutorial, it can be well adapted into templates.

    ( Reply )
  30. PG

    agilius October 30th

    I like it. I think I might learn this by following each step, maybe it will help in some of my projects :) .

    Btw, “The HTML amd CSS” ? I think it should be “and” not “amd”…

    ( Reply )
  31. PG

    colin October 31st

    “if your new to jquery”

    *hiss* huge pet peeve of mine.

    ( Reply )
    1. PG

      Dustin November 3rd

      can’t expect everyone to be well versed in it or JavaScript ;)

      ( Reply )
  32. PG

    XHTML 7 Turbo November 1st

    Who cares for dragable items on webpages (and to remember by browser what was dropped into another page layout-place)? It is totally unuseful – only good stuff for demonstration (nice looking functionality, but totally not wanted for real web usage – and it requires not only JS and PHP but also DataBase(!)). I do not care for Java Script. I have it disabled in browsers. I was also making great looking ads in JS, but in fact they where always just only ads for users. They need useful and good writen text content only (and only, not just another web page with not intuitive navigation and non-clean optionality). By the way: why can’t author use cookie or cache functionality of html5 (instead of enabling all the sql database engine)?

    ( Reply )
    1. PG

      Phil Gapp (Kneeskrap3r) November 19th

      Not to offend, but I believe over 95% of the population runs js, and I believe that the potential to use video and photo multimedia in the web is just beginning to gain momentum. This is a good momentum by the way, as text is far too slow of a communication medium for our information age. Jquery is a marvelous way of combining our beautifully hand crafted sites with media and subconscious experiences…

      Databases are used for virtually every PHP site out there, and a combination of cookies + DB is perfect (with the balance depending on your implementation). I think you could find some very interesting uses for this type of js, as well as so many other js scripts.

      ( Reply )
  33. PG

    Clinton November 1st

    Save the coords in a cookie would probably be enough. No database connection needed. Simple to implement. Nice to have the database functionality though.

    ( Reply )
  34. PG

    Johan November 2nd

    jquery-ui-1.7.2.custom.min.js ????? That could be anything right?

    ( Reply )
    1. PG

      Dustin November 3rd

      “As a note,the jquery-ui file is a custom build which only includes the core and the draggable interaction functionality.”

      What it is, is noted in the tutorial…

      ( Reply )
  35. PG

    christophe November 7th

    nice job !

    ( Reply )
  36. PG

    Fatih November 12th

    No one mentioned it but I think you need to save it into database only when the page is unloading and there is a change in the initial positions. In a real world application, it will kill your server to post data after each drag-drop. On the other hand, using cookies will not have this problem.

    ( Reply )
  37. PG

    Phil Gapp (Kneeskrap3r) November 19th

    Thank you very much! I now have ideas in my head for a fully dynamic CMS using Jquery, dynamic css, and the Zend Framework…

    ( Reply )
  1. Arrow
    Gravatar

    Your Name
    November 19th