Check out the modified JSFiddle link here: http://jsfiddle.net/wz4hs9qa/2/
Here are the key updates made to your code:
1) Assigned a unique id
to each cell based on its index:
cell.id = "cell_" + i;
2) Corrected a typo in the code:
on_drop.value = "drop(event, this)";
3) Moved the ondragover
attribute from X inside the cell to the cell itself. Enabling dropping on empty cells is crucial.
var on_dragover = document.createAttribute('ondragover');
on_dragover.value = "allowDrop(event, this)";
cell.setAttributeNode(on_dragover);
4)
a) Provided each X with an id
similar to its containing cell's id for proper handling by the drop
event.
b) Added an ondragstart
handler to save the index in the drag-and-drop dataTransfer
object for both newer and older browsers.
function createX(obj){
if (obj.innerHTML == ''){
var id = obj.id.replace("cell", "X");
obj.innerHTML = "<h1 id='" + id + "' style='text-align:center;' draggable='true' ondragstart='saveCell(event, this);'>X</h1>";
} else {
obj.innerHTML = "";
}
}
function saveCell(ev, obj) {
var cell_index = obj.id.substring(2);
try {
ev.dataTransfer.setData("text/plain", cell_index);
} catch (exception) {
ev.dataTransfer.setData("text", cell_index);
}
}
5) Removed the line that cleared X on every drop as it conflicted with the desired behavior:
function allowDrop(ev, obj) {
ev.preventDefault();
//obj.innerHTML = '';
}
6) Enhanced the drop()
function to:
a) Prevent dropping when a cell already contains an X
b) Place an X in the target cell
c) Retrieve the cell index from dataTransfer
to clear the source cell
function drop(ev, obj) {
ev.preventDefault();
if (obj.innerHTML !== '') { // not empty
return false;
} else {
createX(obj);
}
var data;
try {
data = ev.dataTransfer.getData("text/plain");
} catch (exception) {
data = ev.dataTransfer.getData("text");
}
var cell_id = "cell_" + data;
document.getElementById(cell_id).innerHTML = '';
}