PSEC: Drag and Drop List Saving and Loading

PSEC: Drag and Drop List Saving and Loading

I’m finally getting back to this. I’ve been reading articles here and there about the use of jQuery UI, trying to find a succinct reference. The source code samples on the jQuery UI demos page helped: you just invoke a method on the element you want to have a certain UI feature (e.g. sortable()). Behaviors are added magically! This is pretty cool. By using the SORTABLE features of jQueryUI, I have just saved myself at least a week of painstaking work rolling my own drag and drop code.


As I mentioned, the “sortable” behavior is what I want. Specifically, I also would like the “portlet” (portal) style display, which puts multiple elements into one div that can be expanded. That’s probably the quickest way to do it. But I’ll try applying .sortable() to what I already have just to see what happens.

So what do I need to do? First I need to include jQuery UI.

  • Went to jQuery UI Download Site and grabbed a download without a lot of effects. It’s about 600K! Version 1.8.16, good for jQuery 1.3.2+
  • Occurred to me that WordPress already includes jQuery UI…I double checked this on the wp-enqueue docs page. So theoretically I can just enqueue the “sortable” script (which is already registered within WP) and use it.
  • I enqueue the scripts in _main.php. I don’t bother with adding the downloaded version. These are jquery, jquery-ui-core, and jquery-ui-sortable.

So now, I should theoretically be able to just add some code like this:

    jQuery( "#vtasks" ).sortable({
        placeholder: "ui-state-highlight",
        delay: 500

Good lord, it works!


So now I just have to do two things:

  1. convert the VTASKS to Portlets
  2. Be able to save the order.

Let’s work on saving the order first. Right now, only model data is being saved. I’m not saving the order of tasks in the list. How do I even get that order? I think I would use jQuery to grab the content of the #vtasks container, and then walk the list of items returned, pulling the task ID number (which looks like vt1, vt2, and so on) and saving them to an array.

In my markup, the #vtasks div holds other unique divs. Pulling the id from each class would require code like this…

var ids = [];
jQuery("#vtasks").children().each(function(i) {
  ids[i] = jQuery(this).attr('id');

This seems to work. I got confused at first because the “each” function doesn’t iterate in-order, so my debug messages were confusing me by not matching the sortable’s order.

I’m now adding the code in View.js to create a VTaskList structure to save. However, there’s an organizational complication in that the Database is stored in Model, but I want to save View related data. I guess it’s not a big deal.

I need to add “dirty” flags to VTaskList now. Currently, the way dirty is handled is on the item level within model. I don’t think I want to do that for VTasks…the entire VTaskList gets dirtied.

I added dirty management to the View structure. The InvalidateVTaskList() function needs to be called on a change event in the jQuery sortable setup. I used:

change: function(event, ui) { View.InvalidateVTaskList(); }    

I’m adding the dirty checks for VTaskList and am now looking into the save code in _ajax.php, and am wondering where in the database I should save the data. I think this could probably just be a string saved in some “views” table, which doesn’t yet exist.


Spent a LOT of time trying to figure out how to write a new database row if it didn’t already exist. MySQL Community Workbench was helpful in constructing a SQL statement that checked. Wasn’t so helpful in showing me empty results.

For some reason, my SQL query executed through wpdb is completely failing to work. It works as expected in MySQL Community Workbench, but it’s acting weird in my PHP. Very annoying.

Strangely, when I dropped the count from:

$exists = $wpdb->query("SELECT * FROM $table WHERE user_id='".$rarr['user_id']."' AND vkey='vtasklist' LIMIT 1");

…it seemed to work. $wpdb might be returning something weird…oh, duh. It returns the # of rows, not the RESULTS of the query. The wpdb->query() command actually doesn’t return values, but it used to run operations on the database where you’re not intending to inspect the results. Grr.


I was fried, so I took a break.


One thing I noticed earlier, which is unrelated to the current thrust of code development, is that I’m not sending a valid user_id. Or rather, the user_id is 0. This may very well be the WordPress user_id, but let me double-check that.

If I recall, it’s set-up in a script just before the footer is output, because that’s where all the vars are passed. I looked at the wp_users table and confirmed that yes, the user id for me is 1. However, the global $user_ID is set to zero. Or is it? Confirmed…it is. At the point that this script runs, the user_id should be valid. But it is not.

Oh, duh…it is because I am not logged-in…I never added a real check for privileged users. I will add a check called dseah_check_user(), which will send a failure if the user is not allowed to do the fun stuff.

Awesome. Just a little bit closer! Finally, I need to add the code that reads in the VTASKLIST and renders the task in the correct order.


Break break break


So now, it’s time to read-in the VTaskList. I have some initialization code in place already, in the initialization routine. So let’s make sure that data is being sent. I have to assemble a vtasks array from my stored string, using the PHP explode() function to convert it into an array.

Next, I have to modify the initialization from packet to take vtasklists into account. Et voila, it seems to work!

I forgot to mentioned also that the “Views” table stores various views per user_id. The only kind I have defined now is a “vtasklist”, which stores a string of comma-delimited numbers in a TEXT data structure. I imagine there will be other kinds of views.

And THAT, my friends, is a complete round-trip, somewhat functioning drag-and-drop list manager thingy. Although I should handle DELETING and SELECTING items too. But before I do that, I will want to do a code review and turn this project into a plugin.

I also need to do the conversion to Portlets, which was the first thing on the list. But I’m now thinking of a way to do mass data entry that would be a nice diversion from this.