JQuery Datepicker works on dynamic input, but not original input - javascript

I am just learning javascript and html, so I hope this isn't an easy question. I have found solutions to many of my questions on this site (thanks to the community) but this one is stumping me.
I am trying to create a dynamic table where it adds elements when the last element has been filled. There are two components to each element: the date, and a particular code. You click on the data cell to reveal the inputs, then when you hit enter or click away it hides the inputs. My problem is with JQuery's datepicker. See this fiddle:
http://jsfiddle.net/VEL7d/
Problem: The datepicker does not work properly for the original data cell. The first time you click on the date input, the datepicker shows up but does not disappear when you select a date. Then, the second time you try to select the date input for the first data cell the datepicker does not show up at all.
The datepicker works fine for all dynamically generated content, i.e. all data cells generated using javascript are fine. Interestingly, I am even able to grab the date from the input box that the datepicker was linked to, even though the second time you click on the date it shows the original "Date" string.
Things I have tried:
Looking on stackoverflow. I see a number of people have had issues with it before, and I have learned a lot. However, I have not come across this issue before. It seems most people have the problem of attaching the datepicker to dynamically created content, but I do not have that issue.
I've tried moving the .datepicker around to different areas, including an onload section, but it doesn't change anything. I know it is a little redundant to have the .datepicker function called where it is, but that is really just where it ended up as I am typing up this question.
I am sure there are other issues with my code, but I am sure I can figure them out. This datepicker issue related to the first data cell is just really stumping me. Any help is appreciated.
I was hoping not to have to post the code, since there is a lot and I am not sure where the problem might be. Here is the HTML:
<section id="chartData">
<table id="cycle_1">
<tr id="row1">
<td class="dataEntry" id="cycle_1_day_1" cycle="1" cycleDay="1" colRef="gray" colDef="true">
<span id="cycle_1_day_1_dateText" class="dateText">Date</span>
<input id="cycle_1_day_1_dateInput" type="text" style="display: none;" class="dateInput" value="Date">
<span id="cycle_1_day_1_codeText" class="codeText">New</span>
<textarea style="display:none;" class="codeInput" id="cycle_1_day_1_codeInput">New</textarea>
</td>
</tr>
</table>
</section>
Here is the javascript:
<script>
$("#chartData").on("click",".dataEntry",function()
{
var ID=$(this).attr('id');
document.getElementById(ID+"_codeInput").innerHTML = document.getElementById(ID+"_codeText").innerHTML
$("#"+ID+"_codeText").hide();
$("#"+ID+"_codeInput").show();
$("#"+ID+"_dateText").hide();
$("#"+ID+"_dateInput").show();
$("#"+ID+"_dateInput").datepicker();
});
$("#chartData").on("change",".dataEntry",function()
{
//Set the data block to the value of the input box when the input box loses focus
var ID=$(this).attr('id');
var codeInputData=$("#"+ID+"_codeInput").val();
var dateInputData=$("#"+ID+"_dateInput").val();
document.getElementById(ID+"_codeText").innerHTML=codeInputData;
document.getElementById(ID+"_dateText").innerHTML=dateInputData;
if ($("#"+ID).is(":last-child"))
{
//Get the cycle number and day for the selected data cell
var currentCycle = parseInt($(this).attr("cycle"),10);
var currentDay = parseInt($(this).attr("cycleDay"),10);
currentDay = currentDay+1;
//Set up new dateText box
var dateTextNode = document.createElement("span");
dateTextNode.setAttribute("class","dateText");
dateTextNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_dateText");
//Set up new dateInput box
var dateInputNode = document.createElement("input");
dateInputNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_dateInput");
dateInputNode.setAttribute("type","text");
dateInputNode.setAttribute("style","display:none;");
dateInputNode.setAttribute("class","dateInput");
dateInputNode.setAttribute("value","Date")
//Set up new codeText box
var codeTextNode = document.createElement("span");
codeTextNode.setAttribute("class","codeText");
codeTextNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_codeText");
//Set up the new codeInput box
var codeInputNode = document.createElement("textarea");
codeInputNode.setAttribute("style","display:none;");
codeInputNode.setAttribute("class","codeInput");
codeInputNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_codeInput");
//Create the new data cell
var node=document.createElement("td");
node.setAttribute("class","dataEntry");
node.setAttribute("id","cycle_"+currentCycle.toString()+"_day_"+currentDay.toString());
node.setAttribute("cycle",currentCycle.toString());
node.setAttribute("cycleDay",currentDay.toString());
node.appendChild(dateTextNode);
node.appendChild(dateInputNode);
node.appendChild(codeTextNode);
node.appendChild(codeInputNode);
document.getElementById(ID).parentNode.appendChild(node);
document.getElementById("cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_codeText").innerHTML="New";
document.getElementById("cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_codeInput").innerHTML="New";
document.getElementById("cycle_"+currentCycle.toString()+"_day_"+currentDay.toString()+"_dateText").innerHTML="Date";
if ($("#"+ID).parent().parent().is(":last-child"))
{
document.getElementById(ID).parentNode.parentNode.parentNode.innerHTML += "<br>";
//Create new table
currentCycle = currentCycle+1;
var tableNode = document.createElement("table");
tableNode.setAttribute("id","cycle_"+currentCycle.toString());
//Modify the codeTextNode from above for the new table
dateTextNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_1_codeText");
//Modify the codeInputNode from above for the new table
codeInputNode.setAttribute("id","cycle_"+currentCycle.toString()+"_day_1_codeInput");
//Create a new data node for the new table
var node=document.createElement("td");
node.setAttribute("class","dataEntry");
node.setAttribute("cycle",currentCycle.toString());
node.setAttribute("cycleDay","1");
node.setAttribute("id","cycle_"+currentCycle.toString()+"_day_1");
node.appendChild(codeInputNode);
node.appendChild(codeTextNode);
//Create the new table
trNode.appendChild(node);
tableNode.appendChild(trNode);
document.getElementById(ID).parentNode.parentNode.parentNode.appendChild(tableNode);
document.getElementById("cycle_"+currentCycle.toString()+"_day_1_codeText").innerHTML="New";
document.getElementById("cycle_"+currentCycle.toString()+"_day_1_codeInput").innerHTML="New";
}
}
});
// Edit input box click action and enter key
$("#chartData").on({
mouseup: function()
{
return false;
},
keypress: function(e)
{
if (e.keyCode == 13) {
$(".codeInput").hide();
$(".codeText").show();
$(".dateInput").hide();
$(".dateText").show();
$(this).blur();
}
}
},".dateInput, .codeInput");
// Outside click action
$(document).on("mouseup", function()
{
$(".codeInput").hide();
$(".codeText").show();
$(".dateInput").hide();
$(".dateText").show();
$(this).blur();
});
</script>

Related

How to bind 2 input fields dynamically added in a table with Jquery

I am not very familiar with javascript/Jquery Syntax, I would like to bind 2 input text fields that were dynamically added to a table inside a loop. The main goal is to automatically fill the second text field with text from the first one. I was able to do it for 2 static text field by doing that.
$(document).bind('input', '#changeReviewer', function () {
var stt = $('#changeReviewer').val();
stt = stt.replace(/ /g,'.')
$("#changeReviewerEmail").val(stt + "##xxxxxx.com");
});
I have tried a few things but when I try to get the value of the first input, it always returns empty. Thanks.
Check this code
$(document).on('input', '#changeReviewer', function() {
var stt = $('#changeReviewer').val();
stt = stt.replace(/ /g, '.');
$("#changeReviewerEmail").val(stt + "##xxxxxx.com");
});
$('#addbtn').click(function() {
$('div').empty().append(`<input id='changeReviewer'><input id='changeReviewerEmail'>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<button id='addbtn'>add inputs</button>
</div>

jQuery: A button that checks all checkboxes in its own DIV and unchecks all the others

I have a dynamically generated form with groups of checkboxes representing categories of companies. These eventually get plotted on a dynamic chart (not shown here). Each group of companies is in a div, and each div has a button called Only that should check all the checkboxes in its own category (div) and uncheck all the other checkboxes on the page.
Here's a Fiddle with all the code: https://jsfiddle.net/c2kn78a9/
The Only buttons have this code in them:
// Uncheck all checkboxes outside this div
$(this).closest("div").not(this).find('input[type=checkbox]').prop('checked', false).change();
// Check all checkboxes in this div
$(this).closest("div").find('input[type=checkbox]').prop('checked', true).change();
But it's not working. Any idea how to fix this?
Here's the code for the entire page.
<!-- This button is different than the other buttons -->
<button class="button-text" id="customize-button">Open User Settings</button>
<!-- Placeholder for dynamic form -->
<div id="company-selection-form"></div>
<script type="text/javascript">
function toMachineString(humanString) {
var machineString = humanString.replace(/\s+/g, '-').toLowerCase();
machineString = machineString.replace('&','');
return machineString;
}
// Setup the form
var categories = new Map([
['Tech Giants',['Alphabet','Amazon','Apple','Facebook','Microsoft']],
['Handset Manufacturers',['Apple','Samsung','Motorola','Sony']],
['Semiconductors', ['AMD','Intel','Nvidia']]
// ... more ...
]);
// Build company selection form inputs
let companySelectionHTML = '';
for (let category of categories) {
categoryName = category[0];
categoryList = category[1];
// Setup a div to differentiate each category of companies.
// Will be used for turning on/off categories en masse
companySelectionHTML += `<div id="${toMachineString(categoryName)}">\n`;
// Category heading
companySelectionHTML += `<h4>${categoryName}</h4>\n`;
// Only button
companySelectionHTML += `<button class="only" id="btn-only-${toMachineString(categoryName)}">Only</button>\n`;
categoryList.forEach(companyName => {
companySelectionHTML += `
<label class="checkbox-label">
<input id="x-${toMachineString(companyName)}" class="checkbox" type="checkbox" name="company" value="${companyName}" checked>
<label for="x-${toMachineString(companyName)}">${companyName}</label>
</label>`;
});
companySelectionHTML += '</div>\n</div>\n</div>\n';
}
// Append to DOM
const companySelectionId = document.getElementById('company-selection-form');
companySelectionId.insertAdjacentHTML('beforeend', companySelectionHTML);
// Make the ONLY buttons check all the checkboxes in their div and uncheck everything else
$(document).ready(function() {
$(document).on("click", ".only", function() {
// Uncheck all checkboxes outside this div
$(this).closest("div").not(this).find('input[type=checkbox]').prop('checked', false).change();
// Check all checkboxes in this div
$(this).closest("div").find('input[type=checkbox]').prop('checked', true).change();
});
});
</script>
Thanks!
Your .not(this) is trying to filter out the button element from the single closest div. You need to get all div's on the page and remove the closest div to "this" button.
From your JSFiddle like this:
var temp = $(this).closest("div");
$("div").not(temp).find('input[type=checkbox]').prop('checked', false).change();
OR (to avoid a new variable)
$("div").not($(this).closest("div")).find('input[type=checkbox]').prop('checked', false).change();
Matt G's solution works fine, it deselects all the checkboxes on the page.
I'd suggest to further refine it by first narrowing the selection to only your #company-selection-form
`$("#company-selection-form")
.find("div")
.not($(this)
.closest("div"))
.find('input[type=checkbox]')
.prop('checked', false)
.change();`
Nevertheless, allow me to suggest that you're maybe wasting your time learning this stuff. This programming paradigm is too problematic and anachronistic. It's slow, gets out of hand very quickly, and never brings anything but suffering. Even the slightest update to the UI can force you to revisit (after months sometimes), debug, and rewrite your code. It's never testable, no one would even bother to test this rigorously.
I mean, if your employer holds a gun to your head every day and you have to choose either to do it this way or die, you'd soon choose to die over this ordeal.

Showing Hidden Row in Table

I am using some code based on the following JSFiddle. The intention is to show more information when the user clicks the "Show Extra" link.
The problem that I'm having is that when the link is clicked on all but the bottom row of the table the hidden element is shown briefly and then closes.
I am populating my table using template strings in javascript. Here is the code that I use to add rows to the table:
this.addRecordToTable = function(bet, index, id){
console.log(index);
console.log($.data(bet));
var butId = id.toString();
if (bet.bookies == null){
bet.bookies = "";
}
if (bet.bet == null){
bet.bet = "";
}
var newRow = `
<tr>
<td>${bet.date}</td>
<td>${bet.bookies}</td>
<td>${bet.profit}</td>
<td><button id=${butId}>Delete</button></td>
<td>Show Extra</td>
</tr>
<tr>
<td colspan=\"5\">
<div id=\"extra_${index}\" style=\"display: none;\">
<br>hidden row
<br>hidden row
<br>hidden row
</div>
</td>
</tr>
`
console.log(newRow);
console.log("#"+butId);
$(newRow).appendTo($("#betTable"));
$("#"+butId).click(
function()
{
if (window.confirm("Are you sure you want to delete this record?"))
{
var rec = new Records();
rec.removeRecordAt(index);
$("#betTable tbody").remove();
var c = new Controller();
c.init();
}
});
$("a[id^=show_]").click(function(event) {
$("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
event.preventDefault();
});
}
EDIT:
I had to change $("a[id^=show_]").click to $("a[id=show_"+index).click..., as the event handler was being added to each element every time I added a new element. Thanks to #freedomn-m.
This code:
$("a[id^=show_]")
adds a new event handler to every existing link as well as the new one as it's not ID/context specific so all the show a's match the selector.
You need to add the context (newRow) or use the existing variable(s) as part of the loop that are already defined, eg:
$("a[id^=show_]", newRow)
$("a#show_" + index)
(or any other variation that works).
An alternative would be to use even delegation for the dynamically added elements, eg:
$(document).on("click", "a[id^=show_]", function...
in which case you'd only need to define/call the event once and it would be fired for new elements (ie put that outside the new row loop).

add text input on certain column table when clicked

I'm quite new in jquery table . I have a code that will add text input in certain column that I clicked . In my case ,the column is number 9th .Below is my code :
$('#PtptnFileTblId_1').on( 'click', 'tbody td:not(:first-child)', function (e) {
var id = $(this).attr('id');
var file_id = $(this).attr('name');
var code = $(this).text();
var textrowId = $(this).children("td:nth-child(9)");
textrowId.html("<input type='text' id='callerid' name='callerid' style='width:100px;' value=''/>");
} );
After click on certain row ,I want its column number 9th will add some text fields that enable me to edit its text but the problem is my code seem not working. Before this I use the same code but different ways and it worked.Please help me with my code above .Any help will greatly appreciate
In your event handler, $(this) refers to the cell that was clicked. You can use closest('TR') to retrieve the table row:
$('#PtptnFileTblId_1').on('click', 'tbody td:not(:first-child)', function (e) {
...
var cell = $(this).closest('TR').children('td:nth-child(9)');
cell.html("<input type='text' id='callerid' name='callerid' style='width:100px;' value='' />");
});

Execute function on second click in jquery

I have a calendar button that on click opens up a date picker and places the date into an input text box. What I want to happen, is have a second text box auto-fill with the date 30 days into the future. What I am having trouble with is getting this to work with jquery.
HTML:
<tr>
<td align = "center">Entry Date From: <input id="ENTRYDATEFROM" name="ENTRYDATEFROM" type="text" maxLength="10" size="12" value="">
<img height="20"src="calendarsrc" id="entrySrc"></td>
<td align = "center">Entry Date To: <input id="ENTRYDATETO" name="ENTRYDATETO" type="text" maxLength="10" size="12" value="">
<img height="20"src="calendarsrc" id="entrySrc2"></td>
</tr>
JQUERY:
$(document).ready(function() {
$("#entrySrc").click(function(){
gAnytime.fPopCalendar(document.myform.ENTRYDATEFROM);
});
$("#entrySrc2").click(function(){
gAnytime.fPopCalendar(document.myform.ENTRYDATETO);
});
//Tried this but had no success
//$(document).on("change", "#entrySrc", populate);
});
function populate(){
var q = $("#ENTRYDATEFROM");
var dateTo = new Date(q.val());
var newDate = new Date(dateTo.setDate(dateTo.getDate() + 30));
var formatted = padNumber(newDate.getUTCMonth() + 1) + '-' + padNumber(newDate.getUTCDate()) + '-' + newDate.getUTCFullYear();
$("#ENTRYDATETO").val(formatted);
}
function padNumber(number) {
var string = '' + number;
string = string.length < 2 ? '0' + string : string;
return string;
}
This is what my GUI looks like before anything is clicked:
This is what happens when I click the #entrySrc calendar button located to the right of the input text box
I can then click on any date that I wish within that calendar box. This will populate the input text box to the left of it.
How can I execute my populate function on/against that second click located within the calendar box?
There may be a very simple solution to this: simply fire the populate() method when #entrySrc changes.
$(document).on("change", "#entrySrc", populate);
or one of these alternatives:
$("#entrySrc").on("change", populate);
$("#entrySrc").change(populate);
note you're passing populate, not populate().
Based on the very poor documentation here: http://calendarxp.net/tutorials/flat/tutorials/PluginsSDK.htm I would guess you need to do the following:
Open your plugins.js file, which is apparently where to hook into a load of global functions (this control is sooooooo old).
Put your code into the fOnChange template (which I gather will be a nearly empty function):
///////////// Calendar Onchange Handler ////////////////////////////
// It's triggered whenever the calendar gets changed to y(ear),m(onth),d(ay)
// d = 0 means the calendar is about to switch to the month of (y,m);
// d > 0 means a specific date [y,m,d] is about to be selected.
// e is a reference to the triggering event object
// Return a true value will cancel the change action.
// NOTE: DO NOT define this handler unless you really need to use it.
////////////////////////////////////////////////////////////////////
function fOnChange(y,m,d,e) {
.... put your code here ....
return false; // return true to cancel the change.
}
What you put in there should be something of practical use. I would suggest generating a custom event like this:
function fOnChange(y,m,d,e) {
var $e = $(e.target); // (or e.originalTarget or whatever you can find with a debugger!)
$e.trigger("calchange");
return false; // return true to cancel the change.
}
This will require that jQuery is included before their js file.
In your code, listen for it like this for all calendars:
$(document).on('calchange', populate);

Categories