I've been working on a side project in my spare time, what little there is, and its come time to work on the UI, which is one of my favorite things to do, but one of the hardest things to get right.
Trying to decide amongst the various ways to delete something, trying to create a user experience that will be pleasant and not knock you out of your workflow. Here are the various methods I've been mulling over with lists of pro's and con's, and because I'm super nice, some javascript code that implements them.
All of the methods I'm going to go over rely on some backend handler that will be communicated with asynchronously to do the heavy lifting of performing the actual delete. The code could be simplified (in some cases greatly) by using jQuery or some other javascript framework, but in the interest of not being dependent on any particular framework, I wrote the code as straight javascript.
All the code depends on two helper methods
/**
* Finds the nearest ancestor of an element with a given tag name
* @param elem [HTML Element] element to find the ancestor for
* @param tag [String] tag name to look up
* @return elem [HTML Element | null] null if can't be found
*/
function get_parent(elem, tag) {
if(elem == null || elem.tagName.toUpperCase() == tag.toUpperCase()) {
return elem;
}
return get_parent(elem.parentNode, tag);
}
/**
* Removes a row when given any node within the row or the row itself
* @param row [HTML Element] row node or any child node of row node
*/
function remove_row(row) {
row = get_parent(row, "tr");
var parent = row.parentNode;
parent.removeChild(row);
}
Method 1: Simple delete
Name
Age
Delete
Amy
24
delete
Matt
23
delete
Zeke
32
delete
[javascript]
function simple_delete(lnk) {
remove_row(lnk);
}
[/javascript]
Pros | Cons |
---|---|
Extremely Simple | Easy to accidentally delete something |
Very little feedback |
Method 2: Confirm Delete
Name
Age
Delete
Amy
24
delete
Matt
23
delete
Zeke
32
delete
function confirm_delete(lnk) {
if(confirm("Really Delete?")) {
remove_row(lnk);
}
}
Pros | Cons |
---|---|
No accidental deletes | Breaks flow |
Easy cross browser implementation | Annoying, focus steal, mousing |
Method 3: Double-click Delete
Name
Age
Delete
Amy
24
delete
Matt
23
delete
Zeke
32
delete
var dblclk_delete_state = null;
function dblclk_delete(lnk, which) {
//Hide everything first
for(var i = 1; i <= 3; ++i) {
var msg = document.getElementById('dblclk_confirm_' + i);
if(msg) {
msg.style.display = 'none';
}
}
if(dblclk_delete_state == which) {
remove_row(lnk);
//No need to clear state, but it can't hurt
dblclk_delete_state = null;
} else {
dblclk_delete_state = which;
document.getElementById('dblclk_confirm_' + which).style.display = 'block';
}
}
Pros | Cons |
---|---|
Easy deletes | Some people double-click out of habit |
Confirm before delete | Double clicks avoid confirmation |
Method 4: Binary Delete
Name
Age
Delete
Amy
24
delete
Matt
23
delete
Zeke
32
delete
//Yes link simply calls remove_row(this)
//This function is called by the delete link and the No link
function binary_message(which) {
var msg = document.getElementById('binary_confirm_' + which);
if(msg) {
if(msg.style.display == 'none') {
msg.style.display = 'block';
} else {
msg.style.display = 'none';
}
}
}
Pros | Cons |
---|---|
No accidental deletes | Breaks flow (less) |
Can be prettied up with qTip | Clicking delete after message appears should perform what action? |
Method 5: Binary Modified
Name
Age
Delete
Amy
24
delete
Matt
23
delete
Zeke
32
delete
//Yes simply calls remove_row(this); like in the non-modified version
//delete link calls this function
function modified_open(which) {
modified_state(which, 'block');
}
//No link calls this function
function modified_close(which) {
modified_state(which, 'none');
}
//Helper function
function modified_state(which, disp) {
document.getElementById('modified_confirm_' + which).style.display = disp;
}
Pros | Cons |
---|---|
No accidental deletes | Breaks flow (less) |
Also can be made pretty | |
Better (?) delete link behavior |
So those are the various methods I'm mulling over now, also whether a delete should remove the row or simply gray it out, should you be able to undo a delete, all kinds of questions. These have serious consequences for my application and are quite outside of the scope of this already way too long post. I think I like Method 4 or 5 the best, can't decide which. Which do you like, is there something that I missed?
Code is hacked together example code, real code will be nicer, possibly even a jQuery plugin
I'm a big fan of "click one and destroy".
ReplyDeleteI'm not a fan of undoing deletes. Undoing deletes gets very tricky in the amount of overhead that you're adding to the application.
Of course, at the end of the day it really depends on the target audience. Who is your audience? Are they experienced users? Developers? My grandma? Each of these target audiences has very different expectations of how a computer will function and very different tolerance levels for their own errors.
The target audience would be business users of all shapes and types. Undoing deletes gets very complicated very quickly, especially if you are cascade deleting children and children's children.
ReplyDeleteClick one and destroy is definitely the easiest, but I know someone will blow away some important record and I'll be on the end of the blame stick.