Prototype observers attached to a class firing multiple times
Thanks in advance for your help guys. I consider myself pretty well-versed in jQuery but as I was helping my sister with her Prototype homework, this frustrated the crap out of me. She couldn't solve it in time so that's moot but for my sanity's sake, I hope you can tell me what's going on.
We were simply creating a netflix-style queue with add, reorder and delete through AJAX. The items were in a UL and had a delete link inside each LI with unique IDs to be used for deletion. Please don't fixate on why we were using text files to save data, etc. - her professor made that impractical choice a requirement, along with a few others...
JS:
function softRefresh() {
$$('.delete').invoke('observe','click',function() { taskDelete(this.id); });
Sortable.create("taskList", { onUpdate: function(list){ saveOrder(list); } });
}
function taskDelete(a) {
var tempArr = a.split('-');
var keyToDelete = tempArr[1];
var output;
var ajaxRequest = new Ajax.Request("todolist.php",
{
method: "post",
parameters: {
action: 'delete',
id: keyToDelete
},
onSuccess: function(response) {
$('taskList').update(response.responseText);
softRefresh();
}
});
}
PHP for the 'delete' action:
$jsonOutput = file_get_contents($myFile);
$fetchedArr = json_decode($jsonOutput);
$newArr = array();
foreach($fetchedArr as $key => $task) {
if(($key != $_POST['id'])) {
array_push($newArr, $task);
}
}
$jsonOutput = json_encode($newArr);
file_put_contents($myFile, $jsonOutput);
$output = '';
foreach($newArr as $key =&g开发者_如何学运维t; $task) {
$output .= '<li id="list_'.$key.'">';
$output .= $task;
$output .= '<a href="#" id="task-'.$key.'" class="delete">X</a>';
$output .= '</li>';
}
echo $output;
The problem was that if I deleted, say, the 2nd item, all the following items would delete as well. Through firebug console I found out that this is because when you click any link of that class ('delete') all the following listeners fire, and keeps deleting the 2nd item off the new list. Can you tell me why and how I can set it so it only fires off the link you click? It drove me nuts all day. I'm used to having .click() on jQuery... much hatred for Prototype at the moment.
Thanks again!
JS:
You shouldn't need the softRefresh
if you set the events well. Likewise, the <ul>
element is never disposed nor replaced so only one Sortable
should be necessary, there is no need to remake that each time.
Event.on('taskList', 'click', '.delete', taskDelete);
Sortable.create("taskList", { onUpdate: saveOrder });
function taskDelete(event, element) {
var id = element.id;
var tempArr = id.split('-');
var keyToDelete = tempArr[1];
new Ajax.Updater({success: 'taskList'}, "todolist.php",
{parameters: {
action: 'delete',
id: keyToDelete
}}
);
}
(Ajax objects in prototype are already POSTs so that doesn't need to be specified. Use of an Updater is neater too. There is little point in wrapping a function call in an anonymous function, it may be the jQuery way but it isn't adding any functionality, javascript functions are objects so use them as such.)
PHP:
I felt $newArr
was a waste of a loop and some memory so here is a shorter way.
$jsonOutput = file_get_contents($myFile);
$fetchedArr = json_decode($jsonOutput);
unset($fetchArr[$_POST['id']]);
// Keys are preserved here, if you need to reorder use:
// $fetchedArr = array_values($fetchArr);
$jsonOutput = json_encode($fetchedArr);
file_put_contents($myFile, $jsonOutput);
foreach($fetchedArr as $key => $task) {
echo '<li id="list_'.$key.'">';
echo $task;
echo '<a href="#" id="task-'.$key.'" class="delete">X</a>';
echo '</li>';
}
精彩评论