Compare multiple date fields on a page through javascript - 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
Related
Javascript Simple If Else innerHTML == 'something' not working
I have a seemingly simple javascript function I am trying to create that checks the value of an elements innerHTML and spits out a value based on the answer, but for the life of me I can't get it to work and don't get any errors. This function is triggered by onclick events and doesn't need to have window.onload added. Any insight anyone could give me would be much appreciated! Here is my HTML <div class="col-md-8 col-xs-9 product-info"> <p id="planTitle" class="bold m-b-2">20 DAY SUPPLY // 40 CAPSULES // FMF</p> <p>Price: <span class="pull-right" id="plan-amount">$79</span></p> <p>Tax: <span class="pull-right">Included</span></p> <p id="shipping-line">Shipping: <span class="pull-right" id="cart-shipping-cost">$9.99</span></p> <p class="hidden">Coupon: <span class="pull-right" id="coupon-code">firstmonthfree20day</span></p> </div> And my Javascript function updateShippingCost(country_region) { var url; var kkdk = ''; var planTitleesd = document.getElementById('planTitle').innerHTML; console.log(planTitleesd); if (planTitleesd == '10 Day Supply // 20 Capsules // FMF') { kkdk = '5.99'; console.log(kkdk); } else if (planTitleesd == '20 Day Supply // 40 Capsules // FMF') { kkdk = '9.99'; console.log(kkdk); } else if (planTitleesd == '30 Day Supply // 60 Capsules // FMF') { kkdk = '14.99'; console.log(kkdk); } } Oddly, console.log(planTitleesd) returns a value, such as "20 DAY SUPPLY // 40 CAPSULES // FMF" but all the other console.log(kkdk) do not. Thanks for your help!
I have updated the original question with the relevant HTML, sorry about that. You are doing a case-sensitive comparison. You've indicated that the resultant value is all caps, while you're comparing it to Title Case. Consider doing a case-insensetive comparison by calling toLowerCase on both operands before comparison. Also, please actually post your markup. Troubleshooting code questions must contain an MCVE. – CollinD 9 mins ago This was the simple answer to the simple question I was looking for - Thanks CollinD!
Almost for sure you have newline at the beginning/end of planTitleesd. Try to replace console.log(planTitleesd); by console.log('>' + planTitleesd + '<'); to check that. Here is an example: https://jsfiddle.net/324aw9zz/1/ You should avoid any spaces/newline between the tag opener/closer and the text itself: <th id=planTitle>lala</th> instead of <th id=planTitle> lala </th>
Why not do something more along the lines of: Using .indexOf() to check for one (or multiple) Strings? function updateShippingCost(country_region) { var url; var kkdk = ''; var planTitleesd = document.getElementById('planTitle').innerHTML; if ( planTitleesd.indexOf('10 Day') > -1 && planTitleesd.indexOf('20 Capsules') > -1 ) { kkdk = '5.99'; } else if (planTitleesd.indexOf('20 Day')) { kkdk = '9.99'; } else if (planTitleesd.indexOf('30 Day')) { kkdk = '14.99'; } } I also agree that you should remove the case sensitive strings, as, (once again), typos and the like can occur. Chances are there is just a typo in the value, or perhaps an empty return/newline you may be looking over. Make sure all Carriage Returns and more are removed from the response. Seeing as, some items may actually add one that you do not notice. (Such as an openly tabbed div) It sounds like this app is a store, something that could get pretty big. I would suggest is maybe an object that returns back the result you need. The following a JSFiddle that I feel would simplify your process if you could create a proper JSON object. https://jsfiddle.net/0sscf798/ function updateShippingCost(country_region) { var url; var kkdk = ''; var planTitleArr = []; var planTitleObj = {}; var planTitleesd = document.getElementById('planTitle').innerHTML; // This would most likely be a JSON response of items from the page/category planTitleObj = { "10 Day Supply": { "20 Capsules": { "FMF": 1.23 } }, "20 Day Supply": { "20 Capsules": { "FMF": 4.56 } } }; planTitleArr = planTitleesd.split(" // "); var price = planTitleObj[planTitleArr[0]][planTitleArr[1]][planTitleArr[2]] || "There is a problem with the price." alert("The Price is: " + price); } updateShippingCost('');
Sort java script array of formatted date
I have an javascript array of date which is formatted in a particular way like MM/DD/YYYY. How can I use javascript sort function to sort this array?
You can use Array.sort, but you need to pass a custom comparison function which converts the values to Dates and compares those, instead of just the string value: var arr = ['07/01/2014', '04/02/2014', '12/11/2013']; arr.sort(function(a, b) { // convert both arguments to a date var da = new Date(a); var db = new Date(b); // do standard comparison checks if(da < db) { return -1; } else if(da > db) { return 1; } else { return 0; } }); // print the result var result = document.getElementById('result'); for(var i = 0; i < arr.length; ++i) { result.value = result.value + '\n' + arr[i]; } <textarea id="result" rows="5" cols="50"></textarea>
Are the dates stored as strings or as Date objects? You can convert each string into a date object by using the Date constructor like new Date('MM/DD/YYYY'). This will give you Date objects and make it much easier to compare. To compare Dates and sort them, just grab their values using the getTime() function to get their value in milliseconds and compare the numbers.
How to do parellel arrays with following information
For this question, it might be a little vague, because i just dont understand it at all, its probably the wording.. from what i learn in class it seems a lot harder. So im lost as to where to begin.. if someone can help walk me through it easier i would appreciate it! Question: Design a Program that will read the same parts inventory file described in the problem 6. the parts are: (Record code, part number, part description, and inventory balance) validate the record code and part number on each record, and print the details of all valid records whose part numbers fall within the value AA3000 and AA3999 inclusive. Also print a count of these selected records at the end of the parts listing. Now, i hope you can understand what its asking because i sure dont. Any help or a small walk through would be awesome. This is the code i am supposed to start out from that was given to me. var Rec_Code = new Array(11,11,11,12,11,12,11,13,11,14); var Numer = new Array(2000,3000,3003,3008,3999,2000,1090,3678,3777,3543); var Alpha = new Array("AA","AA","AX","AA","AA","AA","AB","AA","AN","AA"); var Desc = new Array("X","L","S","F","R","U","T","N","Q","Y"); var Inv_Bal = new Array(12,13,14,23,34,56,32,45,67,77); also, this was given to me, which is basically what i have to do, but dont know how to completely do it. use the vars that I provided to create 5 parallel arrays, RecCode, AlphaPart of part number, Numeric part of the part number,Description and Inventory. You need to search the first 3 arrays for: RecCode of 11 AlphaCode of 'AA': Numeric Code betweewn 3000 - 3999 inclusive when you find a match increment a count and display the Description and Inventory.
Assuming that all arrays are the same length and sorted appropriately, you can loop over one and display the information you need: var count = 0; for(var i = 0; i < Rec_Code.length; i++) { if(Rec_Code[i] == 11 && Alpha[i] == 'AA' && (Numer[i] >= 3000 && Numer[i] <= 3999)) { console.log(Desc[i]); console.log(Inv_Bal[i]); count++; } }
var Rec_Code = new Array(11,11,11,12,11,12,11,13,11,14); var Numer = new Array(2000,3000,3003,3008,3999,2000,1090,3678,3777,3543); var Alpha = new Array("AA","AA","AX","AA","AA","AA","AB","AA","AN","AA"); var Desc = new Array("X","L","S","F","R","U","T","N","Q","Y"); var Inv_Bal = new Array(12,13,14,23,34,56,32,45,67,77); var count = 0; for(var i = 0; i < Rec_Code.length; i++) { if(Rec_Code[i] == 11 && Alpha[i] == 'AA' && (Numer[i] >= 3000 && Numer[i] <= 3999)) { console.log(Desc[i]); console.log(Inv_Bal[i]); count++; } }
Letters to predefined numbers conversion in one window
) I have searched high and low, but i can´t find what i need. Or i´m to stupid to get it right ;-) I need a page with several input boxes where i can type some text, and then an output area below each input, that shows the text converted to some predefined numbers. example: input: abcde fghi æøå (i need all kinds of characters like .,/: etc.) output: 064 065 066 067 068 032 So it needs to convert like this: "a"="064 " "b"="065 " "space"="032 " (and yes, each number in output needs to be separated, or a space added after each number) I have tried some different cipher guides in both php and javascript, but can´t get it to work. I did do an Excel document that could do some of it, but it had a limited amount of characters it could convert, then it started behaving weird. So i thought maybe PHP was the answer! Any help is very appreciated /Rasmus
In the spirit of elclanrs deleted answer, and for posterity: <script> // Using standard for loop function stringToCharcodes(s) { var result = []; function pad(n){ return (n<10? '00' : n<100? '0' : 0) + n;} for (var i=0, iLen=s.length; i<iLen; i++) { result.push(pad(s.charCodeAt(i))); } return result.join(' '); } // Using ES5 forEach function stringToCharcodes2(s) { var result = []; function pad(n){ return (n<10? '00' : n<100? '0' : 0) + n;} s.split('').forEach(function(a){result.push(pad(a.charCodeAt(0)))}); return result.join(' '); } </script> <input onkeyup="document.getElementById('s0').innerHTML = stringToCharcodes(this.value);"><br> <span id="s0"></span> Edit If you want a custom mapping, use an object (I've only included 2 characters, you can add as many as you want): var mapChars = (function() { var mapping = {'198':'019', '230':'018'}; return function (s) { var c, result = []; for (var i=0, iLen=s.length; i<iLen; i++) { c = s.charCodeAt(i); result.push(c in mapping? mapping[c] : c); } return result.join(' '); } }()); alert(mapChars('Ææ')); // Using the character code for mapping seems to be a reasonable solution, using the actual character may be subject to different page character encoding.
jQuery custom validation comparing the sequences of multiple inputs
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.