Currently when the mouse is dragged over a cell, the code below will highlight permissible cells to drag the selected piece to.
I need to modify the code to include clicking as well. For example, when the mouse is dragged over a cell, permissible cells are highlighted. When the same cell is clicked the permissible cells will remain highlighted until either the original cell is clicked again or until one of the highlighted locations is click where upon the image will appear. How can I do this?
Thanks.
Current fiddle.
HTML:
<table border="1" id="tbl">
<tr>
<td ></td>
<td bgcolor=#000000 ></td>
<td class="items p1 p3"><img src="http://icons.iconarchive.com/icons/deleket/soft- scraps/32/Button-Blank-Red-icon.png"/></td>
</tr>
<tr>
<td bgcolor=#000000 ></td>
<td class="items p1"></td>
<td class="items p3" bgcolor=#000000 ></td>
</tr>
<tr>
<td class="piece" id="p1" ><img src="http://icons.iconarchive.com/icons/deleket/soft-scraps/32/Button-Blank-Gray-icon.png"></td>
<td bgcolor=#000000 ></td>
<td class="piece" id="p3" ><img src="http://icons.iconarchive.com/icons/deleket/soft-scraps/32/Button-Blank-Gray-icon.png" ></td>
</tr>
</table>
jQuery:
$('img').draggable({ });
$('#tbl td').droppable({
hoverClass: 'over',
drop: function(event, ui) {
if ($(this).css("background-color")==='rgb(255, 255, 0)') {
$(this).children('img').remove();
var cell = ui.draggable.appendTo($(this)).css({
'left': '0',
'top': '0'
});
$('img').draggable('disable');
} else {
ui.draggable.draggable('option','revert',true);
}
$("td").each(function() {
var id = $(this).attr("id");
$("."+id).css("background", "");
});
}
});
$(".piece").mouseover(function() {
id = $(this).attr('id');
$("."+id).css("background", "yellow");
}).mouseleave(function() {
id = $(this).attr('id');
$("."+id).css("background", "");
});
I think this adds the functionality you're looking for:
jsFiddle
JS
var imgs = $('img');
imgs.draggable({ });
$('#tbl td').droppable({
hoverClass: 'over',
drop: function(event, ui) {
var cell = $(this);
var img = ui.draggable;
if (cell.hasClass("yellow")) {
cell.children('img').remove();
img.appendTo(cell).css({
'left': '0',
'top': '0'
});
img.draggable('disable');
} else {
img.draggable('option','revert',true);
}
$('.yellow').removeClass('yellow');
setUpHover();
}
});
imgs.click(function(){
//the image we just clicked on
var img = $(this);
//The cells we can move our image to.
var cells = $("." + img.parent().attr('id'));
//disable dragging of other images while this one is in focus
imgs.not(img).draggable('disable');
//disable the hover event so that we don't lose our highlighted cells
imgs.unbind('hover');
//add a dynamic click event to the cells we're allowed to click on.
cells.click(function(){
//re-enable dragging for all images
imgs.draggable('enable');
//remove the dynamic click event and remove the yellow background
cells.unbind('click').removeClass('yellow');
//add the image to the cell.
$(this).html(img);
//re-bind the hover event.
setUpHover();
});
});
function setUpHover(){
imgs.unbind('hover').hover(function() {
var id = $(this).parent().attr('id');
$("."+id).addClass("yellow");
}, function() {
var id = $(this).parent().attr('id');
$("."+id).removeClass("yellow");
});
}
setUpHover();
CSS
#tbl td { width:32px; height:32px;}
.over { background-color: red; }
.yellow {
background-color:yellow !important;
}
Related
I have an application whereby when the user clicks on Add New Item button rows are added dynamically using Javascript and each input field in the row added dynamically has a unique id and this works fine.
When any number on the table on the left is clicked it is populated dynamically in the row on the left. When another number on the table on the right is clicked it populates on the single input on the right (after the plus icon).
When I hover over the 1st row the background color changes to green including the corresponding match on the table on the left which works fine.
Am trying to add a logic whereby
a.) if the user clicks on Add New Item button to add a new row (the row is added according to the format of the 1st row).
b.) After the user clicks on any td number on the 2 tables (right and left) and their values are populates in the rows dynamically (value on the left table populates in the row before + sign and value in the right table populates in the right table after + sign), when the user hovers over the values on the rows their background color should change immediately and conform to the values of the tables they were previously chosen from...
NB ~ Basically I want the behavior on the 1st row (after mouseover when inputs are filled from respective tables) to be simulated across proceeding rows that are added dynamically after the button is clicked.
JsFiddle link: Js Fiddle
~ Kindly assist on this quite challenging task..
Javascript code which is commented to show my steps in the task
//Add row input fields dynamically on button click
// Starting number of inputs
let count = 5;
// Wrapper
const wrapper = document.querySelector("#wrapper");
document.querySelector("#btn").addEventListener("click", () => {
const container = document.createElement("div");
for (let i = 0; i < 5; i++) {
// Increment the count to ensure that it is unique
count++;
// Create new `<input>` element
const input = document.createElement("input");
input.type = "text";
input.name = count;
input.size = "4";
input.id = `inp${count}`;
container.appendChild(input);
// Optional: add empty whitespace after each child
container.append(document.createTextNode(" "));
}
wrapper.appendChild(container);
});
//END creating rows dynamically
let currentInput = 1;
let bonusInput = 1;
//Left table on click event
$("#table1 td").on("click", function(event) {
//gets the number associated with the click
let num = $(this).text();
//Populate it in 1st row input fields (before plus sign)
$("#inp" + currentInput++).attr("value", num);
});
//Right table on click event
$("#table2").on("click", function(event) {
//gets the number associated with the click
let bon = event.target.textContent;
//Populate it in 1st row input fields (after plus sign)
$("#bonus" + bonusInput++).attr("value", bon);
});
//Manipulate background colors of rows with corresponding tables they were
//selected on hover in and hover out
$("input").hover(
function(event) {
let parent = $(this).parent();
$(parent.children()).each(function(index, element) {
let num = $(element).val();
//console.log(num);
if (num) {
//Change input color on hover
$(this).css("backgroundColor", "green");
//Change left table bgcolor on hover
$("#table1 td").each(function() {
if ($(this).text() === num) $(this).css("backgroundColor", "green");
});
// $("#table2 td").each(function() {
// if ($(this).text() === num) $(this).css("backgroundColor","green");
// });
}
});
},
function(event) {
//Change input color on hover out
let parent = $(this).parent();
$(parent.children()).each(function(index, element) {
$(element).css("backgroundColor", "white");
});
//Change left table bgcolor on hover out
$("#table1 td").each(function() {
$(this).css("backgroundColor", "orange");
});
}
);
When you use the .hover()-helper, the event-listeners are created and bound to the items that are available at the moment of creation. All inputs that are created after that are ignored. You have to assign/activate the hover-behaviour for them, when you create/append the new inputs.
//Add row input fields dynamically on button click
// Starting number of inputs
let count = 0;
// Wrapper
const wrapper = document.querySelector('#wrapper');
document.querySelector('#btn').addEventListener('click', () => {
// Increment the count to ensure we have unique inputs
count++;
const container = document.createElement('div');
for (let i = 1; i <= 5; i++) {
let input_index = (count * 5) + i;
// Create new `<input>` element
const input = document.createElement('input');
input.type = 'text';
input.name = input_index;
input.size = '4';
input.id = `inp${input_index}`;
$(input).hover(onInputHoverIn, onInputHoverOut);
container.appendChild(input);
// Optional: add empty whitespace after each child
container.append(document.createTextNode(' '));
}
// Bonus-Input
container.append(document.createTextNode(' + '));
let input_index = count + 1;
// Create new `<input>` element
const input = document.createElement('input');
input.type = 'text';
input.name = `bonus${input_index}`;
input.size = '4';
input.style.marginLeft = '20px';
input.id = `bonus${input_index}`;
$(input).addClass('bonus-input');
$(input).hover(onInputHoverIn, onInputHoverOut);
container.appendChild(input);
wrapper.appendChild(container);
});
//END creating rows dynamically
let currentInput = 0;
let bonusInput = 0;
//Left table on click event
$("#table1 td").on('click',function(event){
if (currentInput >= ((count + 1) * 5)) {
return;
}
currentInput++;
//gets the number associated with the click
let num = $(this).text();
//Populate it in 1st row input fields (before plus sign)
$("#inp" + currentInput).attr("value",num);
});
//Right table on click event
$("#table2").on('click',function(event){
if (bonusInput >= (count + 1)) {
return;
}
bonusInput++;
//gets the number associated with the click
let bon = event.target.textContent;
//Populate it in 1st row input fields (after plus sign)
$("#bonus" + bonusInput).attr("value",bon);
});
//Manipulate background colors of rows with corresponsing tables they were
//selected on on hover in and hover out
function onInputHoverIn(event) {
let parent = $(this).parent();
$(parent.children()).each(function (index, element) {
let num = $(element).val();
let isBonus = $(element).hasClass('bonus-input');
//console.log(num);
if (num) {
//Change input color on hover
$(this).css("backgroundColor","green");
if (!isBonus) {
//Change left table bgcolor on hover
$("#table1 td").each(function() {
if ($(this).text() === num) $(this).css("backgroundColor","green");
});
} else {
//Change left table bgcolor on hover
$("#table2 td").each(function() {
if ($(this).text() === num) $(this).css("backgroundColor","green");
});
}
}
});
}
function onInputHoverOut(event) {
//Change input color on hover out
let parent = $(this).parent();
$(parent.children()).each(function (index, element) {
$(element).css("backgroundColor","white");
});
//Change left table bgcolor on hover out
$("#table1 td, #table2 td").each(function() {
$(this).css("backgroundColor","orange");
});
};
$("input").hover(onInputHoverIn, onInputHoverOut);
table {
border-collapse: collapse;
border: 5px solid black;
width: 100%;
}
td {
width: 50%;
height: 2em;
border: 1px solid #ccc;
background-color:orange;
text-align:center;
vertical-align:middle;
font-weight:bold;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--Table on the left -->
<div style="width: 140px; float: left;">
<table id="table1">
<tbody>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>9</td>
<td>10</td>
</tr>
</tbody>
</table>
</div>
<!-- Rows on the right-->
<!--2nd table-->
<div style="width: 140px; float: left; margin-left: 12px;">
<table id="table2">
<tbody>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>9</td>
<td>10</td>
</tr>
</tbody>
</table>
</div>
<!-- Rows on the right-->
<!-- Make sure each input has a unique id-->
<div style="clear: both;">
<div id="wrapper">
<div>
<input type="text" name="1" size="4" id="inp1" value="">
<input type="text" name="2" size="4" id="inp2" value="">
<input type="text" name="3" size="4" id="inp3" value="">
<input type="text" name="4" size="4" id="inp4" value="">
<input type="text" name="5" size="4" id="inp5" value=""> +
<input class="bonus-input" style="margin-left: 20px;" type="text" name="bonus1" size="4" id="bonus1" value="">
</div>
</div>
<button type="button" id="btn">Add new input group</button>
</div>
I've successfully created 3 view boxes using an html table. Each view can be hidden. Now I'd like to have each views width and height to be resizable, pretty much exactly like how its done in JSFiddle where each code editing box can be resized. I found a jQuery widget but it only allow for the columns to be resized and not the boxes. I also found this but it was not implemented with a table http://www.bootply.com/RwnUXIcLap . Here's what I have so far https://jsfiddle.net/3waurzbf/ .
var tds = document.getElementsByTagName('td');
var inputs = document.getElementsByTagName('input');
var rows = document.getElementsByTagName('tr');
console.log(inputs);
console.log(tds);
var changeView = function () {
for (var i = 0; i < inputs.length; i++) {
if (!inputs[i].checked) {
if (tds[i].style.display !== 'none') tds[i].style.display = 'none';
} else {
if(tds[i].style.display === 'none') tds[i].style.display = '';
}
}
if (!inputs[0].checked && !inputs[1].checked) rows[0].style.display = 'none';
else rows[0].style.display = '';
if (!inputs[2].checked) rows[1].style.display = 'none';
else rows[1].style.display = '';
};
changeView();
//$("#views-table").colResizable({liveDrag:true});
html {
height: 100%;
}
body {
height: 100%;
}
table {
width: 100%;
height: 90%;
}
table td {
text-align: center;
border: 1px solid black;
}
#views-container {
height: 10%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>View 1</td>
<td>View 2</td>
</tr>
<tr>
<td colspan="2">View 3</td>
</tr>
</table>
<div id="views-container">
<input type="checkbox" checked="checked" onclick="changeView()"><label>View 1</label>
<input type="checkbox" checked="checked" onclick="changeView()"><label>View 2</label>
<input type="checkbox" checked="checked" onclick="changeView()"><label>View 3</label>
</div>
You can use jQuery UI .resizable(), although it's a bit tricky with table display and requires a little extra code.
Check out this working fiddle: https://jsfiddle.net/18k3umpp/3/
I've added a couple ids to View 1 and View 2:
<tr>
<td id="v1">View 1</td>
<td id="v2">View 2</td>
</tr>
Then try this:
$(window).on("load resize", function() {
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var v1Width = $("#v1").width()
$("#v1").resizable({
minWidth: 50,
maxWidth: windowWidth - 80,
maxHeight: windowHeight * (.83),
handles: "e, s"
}).on("resize", function() {
if (v1Width == $("#v1").width()) {
$("#v2").height(0)
}
v1Width = $("#v1").width()
});
$("#v2").resizable({
maxHeight: windowHeight * (.83),
handles: "s"
}).on("resize", function() {
$("#v1").height(0)
});
});
Of course you can adjust the minWidth,maxWidth, and maxHeight options to whatever your needs are.
I have an HTML table with the following structure:
<tr>
<td>123</td>
<td ondblclick="makeeditable(this);">this is some text</td>
<td><span ondblclick="makeeditable(this);">this is some more text</span><span>flag</span></td>
</tr>
I am writing a JQuery snippet to make second <td> and the first <span> in the third <td> user-editable with a double-click (for what it's worth, the table is being generated dynamically):
function makeeditable(cell){
var OriginalContent = $(cell).text();
$(cell).html("<input id='editcell' class='input' type='text' value='" + OriginalContent + "' />");
$(cell).children().first().focus();
$(cell).children().first().keypress(function (e) {
if (e.which == 13) {
var newContent = $(this).val();
$(this).parent().text(newContent);
}
});
$(cell).children().first().blur(function(){
$(this).parent().text(OriginalContent);
$(this).parent().removeClass("cellEditing");
});
}
Using the function above, I am successful in making the cells editable. However, now I need to somehow retrieve the row reference number (text inside the first <td>, 123 in this example) of the cell that was just edited. My question is, how can one reference the first <td> of a row from the context of the second <td> of the same row and from that of a <span> within yet another <td> of the same row?
To access the first TD in the row for either the TD or SPAN, use .closest('tr').find('td:first').
Here's a simplified version of your code:
$('.editable ').dblclick(function() {
var $self= $(this),
OriginalContent = $(this).text();
$self.closest('tr').find('td:first').text('Editing');
$self
.html('<input class="input" type="text" value="' + OriginalContent + '"/>')
.find('input') //the following methods now refer to the new input
.focus()
.keypress(function(e) {
if (e.which === 13) {
$self.text($(this).val());
}
})
.blur(function() {
$self.closest('tr').find('td:first').text('Double-click to edit');
$self
.text(OriginalContent)
});
});
td {
border: 1px solid #ddd;
}
.editable {
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>Double-click to edit</td>
<td class="editable">this is some text</td>
<td><span class="editable">this is some more text</span><span>flag</span>
</td>
</tr>
</table>
var parent = $(cell).parent();
while(parent.get(0).tagName != "TR")
parent = parent.parent();
var referenceLine = parent.children('td')[0];
// here is your reference
console.log(referenceLine.innerText);
Just want to add that Rick Hitchcock's answer is good and well implemented but .parent() and .children() methods are more than 3 times faster than .closest() and .find() methods : check here and run the test.
I'm using Html5 draggable to drag items into different table cells:
http://jsfiddle.net/d1wnk1bg/6/
<table border="1">
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
<tr>
<td><span class="event" id="item1" draggable="true">Item 1</span>
</td>
<td><span class="event" id="item2" draggable="true">Item 2</span>
<span class="event" id="item3" draggable="true">Item 3</span>
</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
$(document).ready(function(){
$('.event').on("dragstart", function (event) {
var dt = event.originalEvent.dataTransfer;
dt.setData('Text', $(this).attr('id'));
});
$('table td').on("dragenter dragover drop", function (event) {
event.preventDefault();
if (event.type === 'drop') {
var data = event.originalEvent.dataTransfer.getData('Text',$(this).attr('id'));
de=$('#'+data).detach();
de.appendTo($(this));
};
});
})
The only problem with this approach is that if you drag 'Item 1' into the cell where 'Item 2' and 'Item 3' are, Item 1 gets appended to the end.
How can I modify this so that 'Item 1' can be added before 'Item 2' or between 'Item 2' and 'Item 3'. I tried going down the rabbit hole of nested draggables but gave up pretty quickly, hoping there's an easier way!
I forked the Fiddle and adjusted the code a bit:
http://jsfiddle.net/gL88q17m/1/
$(document).ready(function () {
$('.event').on("dragstart", function (event) {
var dt = event.originalEvent.dataTransfer;
dt.setData('Text', $(this).attr('id'));
});
$('table td').on("dragenter dragover drop", function (event) {
event.preventDefault();
if (event.type === 'drop') {
var data = event.originalEvent.dataTransfer.getData('Text', $(this).attr('id'));
de = $('#' + data).detach();
if (event.originalEvent.target.tagName === "SPAN") {
de.insertBefore($(event.originalEvent.target));
}
else {
de.appendTo($(this));
}
};
});
})
What I did is checking whether the item was dropped directly into the td in which case the dropped element will be inserted after all the other entries or if it was dropped on top of another item in which case the item is inserted just before the item the dropped item was dropped on.
Adding some padding to the td makes it easier to drop an item directly into the td even if there are already 3 items inside.
table th, table td {
width: 200px;
height:70px;
padding: 5px;
}
table span {
display:block;
background-color: #ccc;
border: 1px solid black;
color: fff;
height: 30px;
width: 100%;
}
I have done some changes after reading your comment. Now it is working like a charm. I will recommend reading this.
$(document).ready(function () {
$(".event").on("dragstart",function(event){
var dt = event.originalEvent.dataTransfer;
var node = event.target;
dt.setData('text/html', node.innerHTML);
dt.setData('text/plain',node.id);
event.stopPropagation();
});
$(".event").on("dragend",function(e){
event.preventDefault();event.stopPropagation();
})
$(".row>td").on("dragenter dragover dragleave",function(e){
event.preventDefault();event.stopPropagation();
})
$(".row > td").on("drop",function(event){
var dragObjId = event.originalEvent.dataTransfer.getData("text/plain");
var data = $("#"+dragObjId);
var dropTarget = $(event.target).closest("td");
$(dropTarget).prepend(data);
});
})
$(document).ready(function() {
$(".event").on("dragstart", function(event) {
var dt = event.originalEvent.dataTransfer;
var node = event.target;
dt.setData('text/html', node.innerHTML);
dt.setData('text/plain', node.id);
event.stopPropagation();
});
$(".event").on("dragend", function(e) {
event.preventDefault();
event.stopPropagation();
}) $(".row>td").on("dragenter dragover dragleave", function(e) {
event.preventDefault();
event.stopPropagation();
}) $(".row > td").on("drop", functiwww.ta3roof.com / on(event) {
var dragObjId = event.originalEvent.dataTransfer.getData("text/plain");
var data = $("#" + dragObjId);
var dropTarget = $(event.target).closest("td");
$(dropTarget).prepend(data);
});
})
i have:
<tr>
<td align="left">Phonenr:</td>
<td align="left"><b>
<label style="color: #662819;" id="phone">911</label>
</b></td>
<td>Change phone</td>
</tr>
how can i edit phonenumber after clicking on a href="#" and changing(which way?) label into textfield/box?
Based on Change Label to Textbox on edit hyperlink click
Live Demo
$(function() {
$('a.edit').on("click",function(e) {
e.preventDefault();
var dad = $(this).parent().parent();
var lbl = dad.find('label');
lbl.hide();
dad.find('input[type="text"]').val(lbl.text()).show().focus();
});
$('input[type=text]').focusout(function() {
var dad = $(this).parent();
$(this).hide();
dad.find('label').text(this.value).show();
});
});
Try:
$('tr a').click(function() {
var label = $(this).parent().prev().find('label');
label.replaceWith('<input type="text" value="211"/>');
return false;
});
if more then one tr have a tag then you should put id on a or on tr.