I have a small javascript program that looks at the value in one select box (id_Decade for the decade) and adjusts the range of values in two other select (range of years for that decade). The html for the page is created by a Django 2.0 application. I am running jQuery as well.
One of the range of years select boxes (id_Date_year) works correctly - the decade is read from id_Decade, the range of years is created, the id_Date_year select boxes are populated correctly, and if there is a pre-selected year in id_date_year, that is preserved.
The problem the other select box, id_Approximate Date_year, does not preserve the pre-selected year value. The years for the decade are loaded correctly, but the pre-selected year is not selected again.
In this picture, it shows the page after loading. The initial decade is 1890, and the pre-selected year is 1894. Note how the Date select boxes have the year 1984 selected, but the Approximate Date boxes have Choose a year selected. Both select boxes have the correct range of years - 1890-1899.
If I change the decade to 1950, then the Date and Approximate Date selects are correct, since the selected year is 1894, and that is not in the decade of the 1950s. Both select boxes have the same range of years - 1950 to 1959.
Both select boxes use the same code. I know that a space is verboten in the id name of an element, but Django is creating that id value, and I have not found a way to change it.
Here is the code:
(function($) {
$(document).ready(function(){
console.log("Made it into update years from decade");
// Get the selected year if there is a Date field
var Date_years = $('#id_Date_year');
var selectedDateYear = Date_years.find(':selected').val();
console.log("selectedDateYear="+selectedDateYear);
// Get the decade selected
var decade1 = $('#id_Decade option:selected').text();
console.log("decade1="+decade1);
// get the years for that decade
newOptions = years_from_decade(decade1);
// update the date select box
update_options(newOptions, Date_years, selectedDateYear);
// Get the selected year if there is an Approximate Date field
var Approximate_years = $("[id='id_Approximate Date_year']");
var selectedApproximateYear = Approximate_years.find(':selected').val();
console.log("selectedApproximateYear="+selectedApproximateYear);
// update the date select box
update_options(newOptions, Approximate_years, selectedApproximateYear);
$('#id_Decade').change(function(){
// chang the years if the decade changes
var decade2 = $('#id_Decade option:selected').text();
console.log("decade2="+decade2);
newOptions = years_from_decade(decade2);
console.log("we have newOptions=");
console.log(newOptions);
update_options(newOptions, Date_years, selectedDateYear);
update_options(newOptions, Approximate_years, selectedApproximateYear);
})
// calculate the years for the decade
function years_from_decade(decade) {
console.log("we have a decade="+decade);
var newOptions = {};
base_year = parseInt(decade, 10);
for (i = 0; i < 10; i++) {
year = base_year + i;
key = year.toString();
newOptions[key] = key;
}
return newOptions;
}
// replace the options with new ones
function update_options(newOptions, target, selectedYear) {
console.log("update_options selectedYear="+selectedYear);
target.find('option:gt(0)').remove(); // remove all options, but not the first
$.each(newOptions, function(key, value) {
target.append($("<option></option>").attr("value", value).text(key));
console.log("value="+value+" selectedYear="+selectedYear);
if (value == selectedYear) {
console.log("got a match! value="+value);
target.val(value).change();
}
})
}
});
})(jQuery);
The console messages for both select boxes are the same. The matching of the pre-selected year works in both cases, but the id_Approximate Date_year select box does not get the pre-selected year selected, whereas the id_Date_year does.
Is this behavior related to the space in the id value? As you can see from my code, I am not an experienced js coder. I am sure there are much better ways to do what I want to do!
Thanks!
Mark
You are correct that you can not use a space in a jQuery selector. If this is what's causing your problem, you can get around it multiple ways:
Using plain JS and wrapping it with $() to convert it to jQuery object
$(document.getElementById('id_Approximate Date_year'))
Using attribute selector $("[id='content Module']")
Escaping the space $('id_Approximate\\ Date_year')
Demo examples:
$('#div one') .html('$(\'#div one\') Successful')
$(document.getElementById('div two')) .html('$(document.getElementById(\'div two\')) Successful')
$("[id='div three']") .html('$("[id=\'div three\']") Successful')
$('#div\\ four') .html('$(\'#div\\\\ four\') Successful')
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div one">Unchanged</div>
<div id="div two">Unchanged</div>
<div id="div three">Unchanged</div>
<div id="div four">Unchanged</div>
Related
Here is my code, it will get all selected values from multi-select drop down list including the previous select values. My question is, how to get final select valus? Thank you!
var devices = new Array();
var device = document.getElementById("deviceCat");
$('#deviceCat option:selected').each(function() {
devices.push($(this).text());
});
For example, if user select 1 first, and then he find that he doesn't need to select 1. So, he turn to select 2 and 4 then, but my code will output 1,2 and 4. What I want is only 2 and 4 .
Here you go:
Demo: JSFiddle
$("#mySelect").on("change",function(){
var devices = [];
$('#mySelect :selected').each(function(i, selected){
devices[i] = $(selected).text();
//OR
//devices.push($(selected).text());
});
alert(devices);
});
I have almost completed this but am stuck on an advanced selector. I am trying to select a label next to a radio button, but its a little more complex than that.
I have a select box. Only radio buttons (and their sibling labels) in which the value of the select matches the name (well part of) of the radio button.
I have a JS fiddle set up, what I am looking to do, is on selection of January, everything except Jan should be hidden, and when i select February, it should change. I'm trying to do this with just the name and no additional classes but if it comes down to it, I can add them.
http://jsfiddle.net/alpha1beta/G9Sz2/2/
Below is my working selector to get the radio button, and now am looking at how to get their + label next to it
$('.radio([name="insights[interview_questions[' + curr_sel + ']]"])').css('display','inline');
Thanks in advance!
Try
var $radios = $('.radio'), $all = $radios.add($radios.nextUntil('.radio'));
$("#interview_month").change(function () {
var $mon = $radios.filter('.radio[name="insights[interview_questions[' + this.value + ']]"]');
var $cur = $mon.add($mon.nextUntil('.radio')).show();
$all.not($cur).hide()
}).change();
Demo: Fiddle
You may want to check the next() function, it returns the next sibling
Try this:
$("#interview_month").change(function () {
$('.radio , label').hide();
var sel = '.radio[name*="' + $("#interview_month").val() + '"]';
$(sel).add(sel+'+label').css('display', 'inline');
});
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>
I have a list of items that I'm trying to "filter" with a set of 4 selects by matching the value of the select options to the classes I have applied to the list items. Right now, I have it working so that each time you choose a new option with any of the 4 selects, the entire list is reset, and only those items with a class that matches the value of the option you just selected is visible. I would like to have it work so that each time a new option is selected from any of the 4 selects, I could filter by the values of all 4 selects, not just the one that was just changed.
Here's what I have right now - any help is appreciated!
$(".sort-options select").change(function() {
var topics = $(this).val();
$(".list-schools li").hide().filter("." + topics).show();
});
$(".sort-options select").change(function() {
var topics = '';
$(".sort-options select").each(function() {
if ($(this).val()) { // Create combined class .opt1.opt2.opt3
topics += "."+$(this).val();
}
});
$(".list-schools li").each(function() {
$(this).toggle($(this).is(topics));
});
});
Right now, the End Date selection is disabled. I want to only enable this when a Start Date is selected.
if( $('#datepicker1').val().length === 0) {
$('#datepicker2').datepicker("disable");
} else {
$('#datepicker2').datepicker("enable");
}
This clearly does not work. If I insert value = 'random date' into my first input field, it works fine. I'm not too sure on how do this. Clearly not as easy as I had hoped.
My other problem, or hope, is to disable the dates including and before the first selection.
You know, pick Start Date, and every date before and said date for the next picker would be disabled. But that is a whole other problem.
You can use something like this:
var end = $('#end').datepicker();
// Defining a function, because we're binding this to two different events
function enableEnd() {
end.attr('disabled', !this.value.length) // Enable the end input element if the first one has anything in it
.datepicker('option', 'minDate', this.value); // Set the minimum date to the date in the first input
}
$('#start').datepicker({
onSelect: enableEnd // Call enableEnd when a date is selected in the first datepicker
}).bind('input', enableEnd); // Do the same when something is inputted by the user
It's not really a good idea to enable the datepicker in the second field only after the first has been filled in, because the user can still add things into the second field manually, and you lose the format validation usually offered by jQuery UI datepicker. Instead, we disable the second input element directly.
See it working here: http://www.jsfiddle.net/yijiang/KwhLw/
Also note that we're using the input event here, because although it has less broad compatibility, is better than the usual methods used for keyboard event capturing. See a full discussion on this here: http://whattheheadsaid.com/tag/oninput
Just try this approach -
$('#datepicker1').datepicker({
//your other configurations.
onSelect: function(){
//enable datepicker 2 over here.
}
});
I would use the getDate method and see if it's null (nothing selected/entered), like this:
if($('#datepicker1').datepicker("getDate") === null)
For the other issue, check out the date range demo for the datepicker, it has a start/end date like you're aiming for.
Well, question is answered. For those who want to know what I have, here it is.
To change a Start Date and an End Date (A date range if you will) into an array of individual dates, I used this:
function createDateRangeArray($strDateFrom,$strDateTo) //Changes a Range of Dates to Specific Dates
{
static $aryRange = array(); //Creates an Array
$iDateFrom = mktime(1,0,0,substr($strDateFrom,5,2), substr($strDateFrom,8,2),substr($strDateFrom,0,4));
$iDateTo = mktime(1,0,0,substr($strDateTo,5,2), substr($strDateTo,8,2),substr($strDateTo,0,4));
if ($iDateTo >= $iDateFrom)
{
array_push($aryRange,date('Y-m-d',$iDateFrom)); // first entry
while ($iDateFrom<$iDateTo)
{
$iDateFrom += 86400; // add 24 hours
array_push($aryRange,date('Y-m-d',$iDateFrom));
}
}
return $aryRange; //Returns to step 1 and adds another value into the array
}
To get every date from my SQL Database and push them into a single array, this was used:
$query = "SELECT startdate, enddate FROM classdetails";
$results = mysql_query($query);
while ($arrays = mysql_fetch_array($results))
{
$aryDates = createDateRangeArray($arrays['startdate'],$arrays['enddate']);
echo "<br />";
}
So now I have managed to get every date range from an entire list of classes and made one huge array.
Now I had to use this array to actually disable the dates. Using the functions of which Yi Jiang has no generously wrote (thank you to everyone who helped me), the next step is:
$(function()
{
//To enable End Date picker only when Start Date has been chosen (And to disable all dates prior of said date)
var end = $('#enddate').datepicker( {numberOfMonths: 3, beforeShowDay: checkAvailability,});
// Defining a function, because we're binding this to two different events
function enableEnd() {
end.attr('disabled', !this.value.length) // Enable the end input element if the first one has anything in it
.datepicker('option', 'minDate', this.value); // Set the minimum date to the date in the first input
}
//End of function
// Datepicker
$('#startdate').datepicker({
numberOfMonths: 3,
beforeShowDay: checkAvailability,
onSelect: enableEnd // Call enableEnd when a date is selected in the first datepicker
}).bind('input', enableEnd); // Do the same when something is inputted by the user
//hover states on the static widgets
$('#dialog_link, ul#icons li').hover(
function() {$(this).toggleClass('ui-state-hover');}
);
});
//End of Function
//Disabling all dates where selected room and speaker is unavailable
var $myBadDates = new Array (<?php foreach($aryDates as $disabledate) { echo " \"$disabledate\","; } echo " 1"; ?>); //Creates the array (The echo " 1"; is merely to close the array and will not affect the outcome
function checkAvailability(mydate){
var $return=true;
var $returnclass ="available";
$checkdate = $.datepicker.formatDate('yy-mm-dd', mydate);
for(var i = 0; i < $myBadDates.length; i++)
{
if($myBadDates[i] == $checkdate)
{
$return = false;
$returnclass= "unavailable";
}
}
return [$return,$returnclass];
}
//End of function
The only thing in my body right now, for testing purposes, are:
<!-- Datepicker -->
<h2 class="header">Datepicker</h2>
<span>
Start Date: <input type="text" id="startdate" />
</span>
<span>
End Date: <input type="text" id="enddate" disabled="disabled" />
</span>
It's long, yes, but it works. Thank you to everyone who helped me get this working.
The edit was me changing a function to a JQuery function that exists (of which for some reason I did not use in the first place); toggleClass. Thanks for picking that out.