jQuery custom validation comparing the sequences of multiple inputs - javascript

I am using jQuery validate plugin to check whether or not the sequence of 3 date inputs (for example) is in ascending order. My approach is to write a loop which compares input dates from the top to the bottom (first check 1st and 2nd, then check 2nd and 3rd).
My question:
how many times do I need to apply this validation rule? Currently, I
applied this rule to the first input. Though, it checked whether or
not my 3 inputs are in sequence. The error messages always showed up
next to the first input. No matter the location of the error.
should I modify the function into only compare itself inputs VS its successor, and apply it all of the inputs except the last one?
update A new question... If I go with question 2. I need to apply this validaton rule n-1 times for the necessary elements (I can also build a new class). My new question is how do I tell jQuery which which two dates should be compared (first check date 1 and date2, second time check date 2 and date 3)?
DEMO
HTML (a table form with three dates inputs)
<form id="form1"><table><tr class = "app_dates"><th><label for = "id_Date_apt"> Application Date 1 (MM/DD): </label></th> <td> <input id = "id_Date_apt" type = "text" value = "01/11" name = "Date_apt"/></td></tr>
<tr class = "app_dates"><th><label for = "id_Date_apt"> Application Date 2 (MM/DD): </label></th> <td> <input id = "id_Date_apt2" type = "text" value = "12/12" name = "Date_apt2"/></td></tr>
<tr class = "app_dates"><th><label for = "id_Date_apt"> Application Date 3 (MM/DD): </label></th> <td> <input id = "id_Date_apt3" type = "text" value = "03/13" name = "Date_apt3"/></td></tr>
<tr><td><input type="submit" value="Submit"><input type="reset" value="Reset"></td></tr></table></form>
JS
$(document).ready(function() {
//create a function used compare the sequence of input values
function isDate() {
var siz = $('input[id^="id_Date_"]').size()
date = []
temp_f = 0
// this for loop compares the secquences of application dates in pairs
for (var i = 0; i < siz - 1; i++) {
j = i + 1
var date1_m = parseFloat($('input[id^="id_Date_apt"]:eq(' + i + ')').val().slice(0, 2))
var date2_m = parseFloat($('input[id^="id_Date_apt"]:eq(' + j + ')').val().slice(0, 2))
var date1_d = parseFloat($('input[id^="id_Date_apt"]:eq(' + i + ')').val().slice(3, 5))
var date2_d = parseFloat($('input[id^="id_Date_apt"]:eq(' + j + ')').val().slice(3, 5))
var date1_full = new Date(1960, date1_m - 01, date1_d)
var date2_full = new Date(1960, date2_m - 01, date2_d)
if (date1_full > date2_full) {
temp = 0
}
else {
temp = 1
}
temp_f = temp_f + temp
} //end of for loop
if (temp_f != siz-1) {
return false;
}
else {
return true;
}
}
//validation////
$.validator.addMethod("dateFormat", function(value, element) {
return isDate();
}, "Inputs are not in sequence");
$("#form1").validate({
submitHandler: function(form) {
SubmittingForm()
},
rules: {
//should I add the validation rule for Date_apt2 and Date_apt3??
Date_apt: {
dateFormat: true
}
}
})
})​
​

What I would do is check each date against its predecessor. Since people usually fill in forms from top down, I'd consider the second date in a pair to be the wrong when when they're out of order. But either way is fine.
You don't need to put an explicit rule for each date in the .validate() call. If you give a form element a class name that matches a validation method, the method will be called automatically. So just give all but the last or first date_aptN elements the class dateFormat.

Related

Datetime array to array with dates, get corresponding time afterwards

Specific situation.. I'm having an array filled with datetimes I pull in via an api.
Users should be able to select a date from a datepicker (only showing dates available in the array) and afterwards see the corresponding time.
So what I've done..
The original array is obtained via php, so before starting to populate the datepicker with possible dates I create an extra array with dates only.
Since I maintain the key's it's possible to put these 2 arrays next to eachother.
Array looks as following:
["8-8-2017,07:00", "26-8-2017,07:00"];
So far so good...
After a user picks a date I trigger this to be able to start digging for the time corresponding that date.
Now it's getting messy...
$('#datepick').datepicker().on("input change", function(e) {
$("#uur").text('');
var selecteddate = e.target.value;
var searchArr = datesArray;
var ind = searchArr.indexOf(selecteddate.toString());
var result = datesArray.filter(function(item) {
return typeof item == 'string' && item.indexOf(selecteddate.toString()) > -1;
});
var afterComma = result.toString().substr(result.toString().indexOf(",") + 1);
var final = afterComma.replace(":", "u");
$("#uur").text("De warming up party gaat van start rond " + final);
});
The result is that this only works on the last element of the array.
Because I'm splitting based on the comma's. Now I know the easiest way to work arround this would be to change the , that's seperating date and time in another symbol but still I'm wondering why this couldn't be easier.
You convert whole array to string every time. You should change following code:
var afterComma = result.toString().substr(result.toString().indexOf(",") + 1);
To this;
var afterComma = item.toString().substr(item.toString().indexOf(",") + 1);
Edit:
I also missed the loop above
//for every item in result, afterComma will refer to related minute string
for (var item in result) {
var afterComma = item.toString().substr(item.toString().indexOf(",") + 1);
// Do rest here
}

jquery hide/show or condiiton failing

Is there anything wrong with the jQuery/JS below? I have an input field aAmt which on change calls below. ${dAmt} = "10000" from DB. It basically converts the number to $ format(eg.. 23 to $23.00) and focuses the value to the input field. Issue is the if loop (if(aAmt >= a_amount)...) fails.
Even if the condition fails it goes to if loops and shows the div which should not happen. I don't see any error in developers console.
$('#aAmt').change(function() {
var aAmt = $("#aAmt").val();
var a_amount = "${dAmt}";
curFormat(aAmt);
if(aAmt >= a_amount)
{
$("#dsDiv").show();
}else{
$("#dsDiv").hide();
}
});
function curFormat(aAmt)
{
var nAmt = Number(aAmt.replace(/[^0-9\.]+/g,""));
var fAmt = '$' + nAmt.toFixed(2).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
document.getElementById("aAmt").value = fAmt;
}
Have you tried to convert a_amount to an int, to be sure to compare two integers together:
var a_amount = parseInt("${dAmt}");

Combine a Date & a Time Column in Google Sheets for a createEvent() function [duplicate]

This question already has an answer here:
How to merge date and time as a datetime in Google Apps Spreadsheet script?
(1 answer)
Closed 7 years ago.
I need to combine two columns into one dateTime column that can be reading by a createEvent function for startDate.
Column F is the date (mm-dd-yyyy) & Column G is the time (HH:mm PM/AM). I am currently combine them in Column H with the following code:
function conCat() {
var sheet = SpreadsheetApp.getActiveSheet();
var numberOfRows = sheet.getLastRow().toString();
var range = sheet.getRange(2,1,numberOfRows,12);
var values = range.getValues();
var consultedAlreadyFlag = sheet.getRange(2,10,numberOfRows,12);
var sheetName = sheet.getSheetName();
//show updating message
consultedAlreadyFlag.setFontColor('red');
var numValues = 0;
for (var row = 2; row < values.length.toString(); row++) {
//check to see if name and type are filled out - date is left off because length is "undefined"
if (values[row][3].length > 0) {
currentStatus = values[row][1];
//check if it's been entered before
if (values[row][9] != 'EMAIL_SENT'){
sheet.getRange(row+2,8,1,1).setValue('=F' +(row+2)+ '+G' +(row+2));
}
else{
//sheet.getRange(row+2,10,1,1).setValue('EMAIL_SENT');
}
numValues++;
}
//hide updating message
consultedAlreadyFlag.setFontColor('green');
}
}
This code isn't working because when someone submits the form, and the code combines the columns, I cannot get the format to come out as "mm-dd-yyyy HH:mm:ss" which I feel I need in order for my createEvent function to work.
How can I get it to combine the two columns to get the format I need?
I wouldn't bother trying to combine the two columns. There's no point in adding another column, I don't think. You can use JavaScript methods like setHours():
function fncAddToCalender() {
var theEventDate = //To Do - Get the Date
var startMin = value from sheet cell
theEventDate.setHours(15); //Sets event date to 3pm
theEventDate.setMinutes(startMin);
var cal = CalendarApp.getDefaultCalendar();
var event = cal.createEvent(calndrTitle, theEventDate, endDate, {
description : theDescrptn,
location : theLocation,
guests : guestToInvite,
sendInvites : true
});
};
The format in the spreadsheet is probably set to "date". And getting the values with Apps Script will probably return a value that's already in a date format. If you have the columns formatted as text, you'd need to change the values to a date.

Compare multiple date fields on a page through javascript

How to efficiently compare dynamic number of dates on a page from a given date?
Consider following code:
<div id="dateFields">
<input type="date" id="date1"/>
<input type="date" id="date2"/>
<input type="date" id="date3"/>
<input type="date" id="date4"/>
<input type="date" id="date5"/>
</div>
<div id="masterDate">
<input type="date" id="comparator"/>
</div>
<button onClick="compareDate()">Compare Now</button>
Consider the dates in div with id="dateFields are in random numbers. Say 5 for now. And the date in div with id="comparator is the date which we need to compare all the dates with.
Now, for example, if the comparator date is set to "March, 2015" and all the values in dateFields are set dynamically by the user (Say "Feb, 2002", "Dec, 2010", "Aug, 2016", "Jul, 2019" and "Nov, 2015"). What is the most efficient and generic code I should write in the function compareDate() so that the output brings all the dates which are greater than the comparator.
Edit:
Here is my javascript function. But, I don't feel that this is the efficient way. And even this is no good for dynamic number of values.
function compareDate() {
var v1 = document.getElementById("date1").value;
var v2 = document.getElementById("date2").value;
var v3 = document.getElementById("date3").value;
var v4 = document.getElementById("date4").value;
var v5 = document.getElementById("date5").value;
var v6 = document.getElementById("comparator").value;
var v7 = [ v1, v2, v3, v4, v5 ];
var result = "";
for (i = 0; i < v7.length; i++) {
console.log(solidify(v7[i]));
if (solidify(v6) < solidify(v7[i])) {
result += v7[i];
}
}
document.getElementById("result").innerHTML = result;
}
function solidify(date) {
var tempResult = '';
for (i = 0; i < date.length; i++) {
if (date.charAt(i) == '-') {
continue;
}
else {
tempResult += date.charAt(i);
}
}
return tempResult;
}
Edit 2:
Explanation of the requirement with example.
There need not be any text-box, it may be just a set of <td>, <p> or may be just a <div> containing number of dates, which may vary from minimum 2 dates to max 50 dates(Say).
I'm just looking for a logic and hence was trying with text-boxes.
For a real time example, consider a City Municipality Management System, which keeps track of monthly deaths that occur in that city. Now, a clerk wants to know the details of citizens who died after 15th of that month, how will he get the data?
The following code does what you are asking, but there are still some requirements that you need to nail down, in order to make it truly "generic" (see below the code):
HTML
<div id="dateFields">
<input type="date" id="date1"/>
<input type="date" id="date2"/>
<input type="date" id="date3"/>
<input type="date" id="date4"/>
<input type="date" id="date5"/>
</div>
<div id="masterDate">
<input type="date" id="comparator"/>
</div>
<div id="results">
Results: <span id="resultDates"></span>
</div>
<button onClick="compareDate()">Compare Now</button>
JavaScript
<script>
function compareDate() {
var aDates = document.getElementById("dateFields").getElementsByTagName("input");
var sCompareDate = document.getElementById("comparator").value;
var dCompareDate = formatDate(sCompareDate);
var result = "";
for (i = 0; i < aDates.length; i++) {
var sCurrDate = aDates[i].value;
if (dCompareDate < formatDate(sCurrDate)) {
if (result.length > 0) {
result += ", ";
}
result += sCurrDate;
}
}
if (result === "") {
result = "No dates less than " + sCompareDate;
}
document.getElementById("resultDates").innerHTML = result;
}
function formatDate(sDate) {
var regMonthYear = /[a-z]{3}, \d{4}/i;
if (regMonthYear.test(sDate)) {
sDate = sDate.replace(",", " 1,");
}
return new Date(sDate);
}
</script>
Things that need to be worked out still:
You must compare Date objects, not strings.
To do what you are trying to do, you must use JavaScript Date objects. Even if you are using am <input> with a type attribute of "date", its value is still a string. If you compare that, it would be like asking if "orange" is less than "house" . . . JavaScript will give you an answer, but it will be, in no way, related to what you are looking for.
The JavaScript Date object has built in comparison functionality that will do exactly what you are looking for.
2 You need to come up with some sort of standard for your date inputs and make sure that you have code to enforce them.
While the Date object is VERY flexible when it comes to what inputs it will accept when you are creating a new instance, it does have its limits. You can look at these two links for more information on valid string formats for creating dates:
the ISO date format - https://msdn.microsoft.com/en-us/library/ie/ff743760%28v=vs.94%29.aspx#ISO
other date parsing rules - https://msdn.microsoft.com/en-us/library/ie/ff743760%28v=vs.94%29.aspx#OtherDateFormats
Once you figured out which one(s) make the most sense for your needs, you really should set a common format (or group of formats) that you want to work with, and enforce that formatting on your inputs with validation rules. If you don't, you will have to add LOTS of logic to validate all of the different possibilities, so that you know that you are going to get a valid Date object when you try to create it.
3 You need to come up with some sort of standard output for your results.
Ideally, if you want to create a truly "generic" date comparison function to meet what you are asking for, you want it to focus solely on the comparison and nothing else. Something like this:
function compareDate(aDateGroup, dComparisonDate)
var aGreaterThanDates = [];
for (i = 0; i < aDateGroup.length; i++) {
if (dCompareDate < aDateGroup[i]) {
aGreaterThanDates.push(aDateGroup[i]);
}
}
return aGreaterThanDates;
}
. . . where aDateGroup is an array of Date objects and dCompareDate is a Date object as well.
The function would take in the dates, compare them, and pass back the ones that passed the test. Then you could cycle through the returned array and process those dates however you needed to.
This would also allow you to pass in dates from any source (i.e., like a collection of the <td>, <p>, and <div> elements that you mentioned in your second update), as long as they were converted to proper Date objects first.
Determine whether or not you need to be flexible in your comparison.
The above "ideal code" could actually be made even "more ideal" by adding some flexibility in the comparison function, by adding a few parameters to indicate what kind of comparison to do:
function compareDate(aDateGroup, dComparisonDate, sCompareDirection, bIncludeComparisonDate)
var aPassedDates = [];
for (i = 0; i < aDateGroup.length; i++) {
if (sCompareDirection === "before") {
if (bIncludeComparisonDate) {
if (dCompareDate >= aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
else {
if (dCompareDate > aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
else if (sCompareDirection === "after") {
if (bIncludeComparisonDate) {
if (dCompareDate <= aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
else {
if (dCompareDate < aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
else {
if (dCompareDate == aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
return aPassedDates;
}
The sCompareDirection parameter would allow you to determine the direction of the comparison. "before" would check for values less than the comparison date, "after" would check for values greater than the comparison date, and any other value (or no value) would check for the dates being equal.
The bIncludeComparisonDate parameter would allow you to include the comparison date as part of the match. A value of true would turn the "greater than" comparison to "greater than or equal to" and the "less than" comparison to "less than or equal to".
Conclusion
Date comparison is actually a fairly common process, but it is also one that requires a LOT of thinking through to make flexible and foolproof. If you don't catch some of these things early, you are asking for a world of hurt down the line, when you try to reuse what you have built and in a situation that doesn't quite match what you originally set up. :)
you can do it in following way :
<script>
function compareDate() {
var v1 = document.getElementById("date1").value;
var v2 = document.getElementById("date2").value;
var v3 = document.getElementById("date3").value;
var v4 = document.getElementById("date4").value;
var v5 = document.getElementById("date5").value;
var v6 = document.getElementById("comparator").value;
var v7 = [ v1, v2, v3, v4, v5 ];
var finalResult = "";
for (k = 0; k < v7.length; k++) {
if (solidify(v6) < solidify(v7[k])) {
finalResult += v7[k];
finalResult += " and ";
}
}
document.getElementById("result").innerHTML = finalResult;
}
function solidify(date) {
var result = '';
for (i = 0; i < date.length; i++) {
if (date.charAt(i) == '-') {
continue;
} else {
result += date.charAt(i);
}
}
return result;
}
</script>
function compareDate() {
var dateFields = document.getElementById('dateFields').getElementsByTagName('input');
var comparatorDate = new Date(document.getElementById('comparator').value);
var rslt = [];
for (var i = 0; i < dateFields.length; i++) {
if (new Date(dateFields[i].value) > comparatorDate) rslt.push(dateFields[i].value);
}
return rslt;
}
This was tested in chrome

Registering clicks on a button

I have created a button in JavaScript with the following details:
<td id='2,A,B,C' onclick='enterKey(this.id)'>2</td>
When the JS is passed through the function an array is created:
string = string.split(',')
meaning string[0] is 2, string[1] is A and henceforth....
The question I wanted to ask is how do I get JS to register multiple presses on the button.
So if the user presses the twice - they get A instead of 2. If they press it three times - they get B. But if they press is 5 times - it reverts back to 2.
Any advice on how I can achieve this? Many thanks in advance!
First off, you have an invalid ID:
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
However, assuming you either revise it to use, say, a period or something else, you can track it but just assigning the "click count" to an attribute on the td. For instance:
<script type="text/javascript">
function incCounter(e){
var count = e.getAttribute('data-clicks') || 0,
id = e.getAttribute('data-clickid').split(',');
e.innerHTML = id[++count % id.length];
e.setAttribute('data-clicks', count);
}
</script>
<td data-clickid="2,a,b,c" onclick="incCounter(this);"></td>
Working Demo
Then read the data attribute to determine which element of the "ID array" you need to reference.
A simple solution would be to declare a global variable outside of the method definition, and increment it on each press.
var count = 0;
function enterKey() {
//Split and whatnot here
var myValue = string[count];
count++;
if(count == 5) {
count = 0;
}
}
You would attach it dynamically somehow. So, for example, if you wanted to do this to all <td> elements:
var elements = document.getElementsByTagName('td');
var i, element;
for(i = 0; element = elements[i]; i++) {
(function(element) {
var data = element.getAttribute('data').split(',');
var numClicks = 0;
element.onclick = function() {
enterKey(data[numClicks++ % data.length]);
};
})(element);
}
Note that I used element.getAttribute('data') instead of element.id; #FelixKling is correct, that's an invalid ID.
Something like this?
var count = 0;
function enterKey( string ) {
string = string.split( "," );
return string[(count++) % string.length];
}

Categories