Javascript Logic Issue in IE - javascript

First I'll explain a little bit about my system here. It's a form to allow children to book onto a series of day courses that run in the school easter and summer breaks. The form allows registration of two children simultaneously, and if the dates for both children are the same, the sibling has a £5 discount for their dates.
On the form, there is a date section which is a series of checkboxes. As you check the checkboxes a total price is calculated at the bottom of the page.
The single child price is £29 and the sibling rate (for those dates that match up to the first child) is £24. There is an additional £16.50 charge for booking onto the horseriding course - but this logic error only extends to the date selection.
For some reason, which I cannot fathom, in Internet Explorer the price for registering 2 children appears £5 less that it should. Here is my code for calculating the dates (the function below is fired onclick of the date checkbox):
function processDates(){
//contentsA and contentsB are used for outputting on the email confirmation
valsA = [], dates_A = document.forms['registerForm']['childADates[]'];
for(var iA=0,elmA;elmA = dates_A[iA];iA++) {
if(elmA.checked) {
valsA.push(elmA.value);
}
}
contentsA = valsA.join(', ');
//this generates a string based on what dates were selected i.e. April 18th, April 19th etc.
var valsB = [], dates_B = document.forms['registerForm']['childBDates[]'];
for(var iB=0,elmB;elmB = dates_B[iB];iB++) {
if(elmB.checked) {
valsB.push(elmB.value);
}
}
contentsB = valsB.join(', ');
//same as contentA but for the second child.
//get the total dates for both children
//fullDates is the number of dates selected (number of checkboxes checked)
fullDates = (valsA.length + valsB.length);
siblingDates=0;
//this detects if entries are matching in the two arrays valsA and valsB
for(var i in valsA) {
for(var j in valsB) {
if(valsA[i]==valsB[j]){
//if there are matching dates, increment a siblingDates value to get a total number of matching dates in the siblingDates variable
siblingDates=siblingDates+1;
}
}
}
//get the amount of dates to be charged at £29
fullDates = fullDates - siblingDates;
fullPrice = fullDates*29;
siblingPrice = siblingDates*24;
totalPrice = fullPrice + siblingPrice;
calcTotal();
}
function calcTotal(){
var horseA = parseInt(document.getElementById("horseridingA").value);
var horseB = parseInt(document.getElementById("horseridingB").value);
var horse = parseInt(horseA+horseB);
//Add the horseriding price
overall = parseFloat(horse*16.5)+totalPrice;
//output the overall total to the form
document.getElementById("totalPrice").innerHTML = overall;
}
UPDATE: This process is run when the user selects one of the checkboxes that correspond to each date. April 18th [], April 19th [] etc. These checkboxes are duplicated for the 2nd child. Upon clicking one of the checkboxes the above functions are run that calculate a total price at the bottom of the screen. In internet explorer, clicking a date for ChildA yields £24 not £29, but only on the FIRST date clicked, all other dates both childA and childB are calculated correctly. The first date choice is £5 less than it should be.
I just used IE to select the first date on the main child side and it gave £24, then unselected the same checkbox which gave £-5
UPDATE 2: Okay! I've narrowed down the problem to the below statement:
fullDates = (valsA.length + valsB.length);
siblingDates=0;
for(var i in valsA) {
alert(valsA[i]);
for(var j in valsB) {
if(valsA[i]==valsB[j]){
alert("does equal");
siblingDates=siblingDates+1;
}else{
alert("does not equal");
}
}
}
Upon clicking the April 18th checkbox, the first alert (valsA[i]) reads April 18th
The second alert reads "does not equal" as expected.
In Internet Explorer the above happens normally as expected but I get an additional set of alerts:
After the above 2 alerts I get a bizarre function alert that alerts of a string length error, it's about four lines of minified code so very difficult to decipher.
Then the same alert appears again.
Then I get "does equal"

Try changing your loop to this:
for (var i=0; i < valsA.length; i++) {
for (var j=0; j < valsB.length; j++) {
if(valsA[i]==valsB[j]){
alert("does equal");
siblingDates=siblingDates+1;
}else{
alert("does not equal");
}
}
}

first up, these lines look wrong, is this how they appear in your code?
for(var iA=0,elmA;elmA = dates_A[iA];iA++)
for(var iB=0,elmB;elmB = dates_B[iB];iB++)
try something like this
for(var iA=0;iA < dates_A.length;iA++){
var elmA = dates_A[iA];
...
}

Related

How to sort elements of array in natural order with mixed (letters and numbers) elements

i am trying to create google-form which is used to register students agreements on practice. Every agreement is registered and got agreement number which format is Last to digits of current year-T-number of agreement at this year/M. For example for now it is 17-T-11/M. The number of agreement currently is written by person which is responsible for practice.
Here is code of script below:
function onChange(e)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var range = sheet.getDataRange();
var values = range.getValues();
var comboValues = ['16-T-105/M'];
// removing titles from 0 column and 1 line (titles)
for (var i = 1; i <= values.length; i++) {
var v = values[i] && values[i][0];
v && comboValues.push(v)
}
// Sort the values
comboValues.sort(
function(a, b) {
if (b.toLowerCase() < a.toLowerCase()) return -1;
if (b.toLowerCase() > a.toLowerCase()) return 1;
return 0;
}
);
Logger.log(comboValues);
// google-form modification
var form = FormApp.openById('1SHgVIosoE34m9cny9EQySljvgnRpzffdFEZe-kzNOzA');
var items = form.getItems();
for (i = 4; i < items.length; i++) {
Logger.log("ID: " + items[i].getId(), ': ' + items[i].getType());
}
form.getItemById('2087613006').asListItem().setChoiceValues(comboValues);
I got issue which is related with lexicographical order. Person which register agreement choose from list last registered agreement number: i tryed to do that last registered agreement number will always be at list top. As time when i started this everything was fine (it started with number 16-T-105/M), but new year come and soon after 17-T-10/M agreement was registered i got issue, that 17-T-10/M was not on list top. Soon i realised that this happens because script use lexicographical order and "thinks" that 2 is more than 10. So i understood that i somehow will have to change that order and do that 2 is less than 10, 11 is less than 101 and so on.
My question is how to do that? I guess that i need to sort array elements in natural order - but i do not have idea how to do this.
I tryed to google how to do it , but result was not satisfactory - maybe my knowledge of coding is pretty limited (i am PhD student of Psychology, not Informatics) :)
Maybe someone will help how to solve that problem.
Updates:
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1FH5qYTrLUNI2SCrcaqlwgu8lzAylaTkZsiALg0zIpCM/edit#gid=1620956794
Link to google-form (Copy of actual form): https://docs.google.com/forms/d/e/1FAIpQLSerJfkv1dgHexUwxppXNyhb46twOZgvEMOIVXSOJoED3SLmyQ/viewform
You should adjust the sorting method to account of the peculiarities of the data. Here is one way to do this: the function splitConvert processes each string, splitting it by non-word characters and then converting what can be converted to integers (and lowercasing the rest). Then the comparison goes through this array one by one.
comboValues.sort(
function(a, b) {
var as = splitConvert(a);
var bs = splitConvert(b);
for (var i = 0; i < as.length; i++) {
if (bs[i] < as[i]) return -1;
if (bs[i] > as[i]) return 1;
}
return 0;
}
);
function splitConvert(str) {
return str.split(/\W/).map(function(part) {
var x = parseInt(part, 10);
return isNaN(x) ? part.toLowerCase() : x;
});
}
This is not the most performance-oriented solution: the split-parse function will be repeatedly called on the same strings as they are being sorted. If this becomes an issue (I don't really think so), one can optimize by having one run of conversion, creating an array of arrays, and then sorting that.

Optimization of a large multiselect list

I have three MultiselectLists
Countries which has 22 values
Cities which has ~800 values
Sites which has ~1700 values
I am using the jquery bootstrap-multiselect library
It is fast enough for what I am trying to do that the user doesn't notice any overhead except in one case when the user selects USA 600 Cities and 1200-1300 sites get checked/selected this takes about 30 seconds in IE, and about 6 seconds in Firefox which is enough for a reasonable person to believe that something is wrong with the page.
I don't want to change the UI of the website at all since this works beautifully in every other case, including when the user hits a "select-all" or "deselect-all" and just wants to run a full report
these are the two functions that take about 90-95% of the time to execute
getInputByValue: function(value) {
var checkboxes = $('li input', this.$ul);
var valueToCompare = value.toString();
for (var i = 0; i < checkboxes.length; i = i + 1) {
var checkbox = checkboxes[i];
if (checkbox.value === valueToCompare) {
return $(checkbox);
}
}
}
getOptionByValue: function(value) {
var options = $('option', this.$select);
var valueToCompare = value.toString();
for (var i = 0; i < options.length; i = i + 1) {
var option = options[i];
if (option.value === valueToCompare) {
return $(option);
}
}
}
and this is the code I use to select all of the options, I have a Dictionary>>(); that I pass from my controller into my view that governs the relationship between the Countries/Cities/ and sites
onChange: function (option, checked, select) {
try{
if (checked == true) {
var t0 = performance.now();
$('#Cities').multiselect('select', Object.keys(CountryCitySite[$(option).text()]),'triggeronChange');
var t1 = performance.now();
list = Object.keys(CountryCitySite[$(option).text()])
var t2 = performance.now();
for(var i = 0; i<list.length; i++)
{
$('#Sites').multiselect('select', CitySite[list[i]])
}
var t3 = performance.now();
}
else if (checked == false) {
$('#Cities').multiselect('deselect', Object.keys(CountryCitySite[$(option).text()]), 'triggeronChange');
list = Object.keys(CountryCitySite[$(option).text()])
for(var i = 0; i<list.length; i++)
{
$('#Sites').multiselect('deselect', CitySite[list[i]], 'triggeronChange')
}
}
}
Some thoughts:
1. maybe in the case of USA I could do an Ajax, and post everything to the server and then return three new selectlists with the appropriate options checked? the problem with this is that I don't see this taking less than like 7 or 8 seconds if not more which is still much too long
var options = $('option', this.$select);
this Jquery selection is several orders of magnitude slower than just using native javascript Document.getelementsbytagname, since I know that all of the checkboxes have unique values maybe I could replace this Jquery selection with native javascript and get all of the checkboxes that way
as a 'hack' I could send two invisible multiselectlists at the very beginning with all of the boxes for USA checked, these invisible multiselects behave exactly the same as the visible ones in most respects but if the user selects USA, these are shown instead of the originals. This actually does work, it makes the website a little slower but since the selection of every other option is so quick it doesn't really matter, it seems like a sub-par solution but this is currently the best I have
if anyone thinks of anything else or can give any advice on this I would be very appreciative
Sincerely Josh

PDF script return value of last non blank field in a group

Trying to teach myself javascript I can do some minor scripts by myself but this one has got me stumped. I have been trying for weeks and cant get anywhere.example image
MY goal is to have the field labeled end item automatically populate with the last item filled in on the list.
I know how to do this in excel but with javascript I am completely lost any guidance would be greatly appreciated thanks in advance.
I have tried this before:
var one = this.getField("a1");
var two = this.getField("a2");
var three = this.getField("a3");
//for all 25 fields
if(two.value==''||two.value==null){
this.getField("a1")}
else if (three.value==''||three.value==null){
this.getField("a2")}
//for all 25 fields
The loop shown below loops over all of your fields. As long as it finds a value, it remembers that value (so "theResult" always contains the currently last found item). If no value is found (in other words, if we find the last item in the list, we simply break and know that "theResult" contains the last real value.
// Start by not having any result
var theResult = null;
// Loop over all fields
for (var theIndex = 1; theIndex < 26; theIndex++) {
// get this field
var theField = this.getField( "a" + theIndex );
// If this field has a value, take it, if not quit our loop
if (theField.value) {
theResult = theField.value;
} else {
break;
}
}

Jquery automatically select next X checkboxes

I'm working on a website for a theater where a customer can reserve tickets.
Choosing a chair works as follows:
You select how many chairs you want in the dropdown menu (we will call this X).
You tick the checkboxes where you want to sit (maximum of X).
Upon having chosen all X checkboxes, the other checkboxes turn grey (unclickable).
There are ofcourse also chairs that have already been reserved. These simply don't have a checkbox. The value of the checkbox is the same as the chair's unique ID.
This works fine except I want the system to automatically tick the next checkboxes (next 3 if the customer has chosen 4).
I have updated my code to this:
var _X = $('#PlaatsenDropdown').val() - 1;
var _id = $(this).id;
var _counter = _id + _X;
for(var i = _id; i <= _counter; i++) {
if($(this).nextAll().is('disabled')) {
alert('No seats available');
} else {
alert('Chairs available');
}
}
The id is also the chair number, so I just take that and do some calculations with it to use in the for loop.
This however, doesn't show me anything. I think there might be something wrong with the calculations but I can't figure out what :S.
You can create an array of ID strings similar to what you've done already. Then loop through the array with the 'disabled' test.
Pseudo code:
val = selected_chair_ID
for (i=0; i < desired_number_chairs; i++) {
search_right.push('#' + val + i);
search_left.push(('#' + val - i);
}
found = true;
for (j = 0; j < search_right.length; j++) { // Check chairs to the right
$(search_right[j]).....// Disabled check
if (disabled...) {
found=false;
}
if (!found) {
check chairs to the left
}
if (!found) // out of luck

Changing If - Else function to return multiple values?

So the JavaScript code below is what I am using to pull data from our automated marketing software Eloqua. This works for single-select drop downs. What I want it to do is work for multi-select drop downs.
I know that the ProductValue variable works. So with that said I am positive that it is in the if(ProductValue == ProductList[i].value) specifically the " .value " since this is calling the value on in the drop-downs. Is there a way to make this multiple? This has been driving me nuts for days.
function CustomerInformation()
{
var ProductValue = "<span class=eloquaemail>MarketingCustomerInformation1</span>"; //Field Merge...Field merge is working
var ProductList = document.getElementById('C_Marketing_Customer_Information1').options; //Calling the contact record field
for(var i=0; i< ProductList.length; i++)
{
if(ProductValue == ProductList[i].value)
{
document.getElementById('C_Marketing_Customer_Information1').value = ProductValue;
break;
}
else
{
document.getElementById('C_Marketing_Customer_Information1').value = "Select";
}
}
}
you could use multiple for loops:
var ProductValue = "<span class=eloquaemail>MarketingCustomerInformation1</span>"; //Field Merge...Field merge is working
var ProductList = document.getElementById('C_Marketing_Customer_Information1').options; //Calling the contact record field
for(var i=0; i< ProductList.length; i++)
{
for(var j=0;j<ProductValue.length;j++)
{
if(ProductValue[j] == ProductList[i].value)
{
document.getElementById('C_Marketing_Customer_Information1').option[i].selected="selected";
}
}
}
Could also add a boolean var to select a default for when nothing gets selected.
BASIC IDEA
The first loop will go through all the values in the multi-select list.
The second loop will go through all the values you pass it (meaning ProductValue will need to be an array of all the values you want selected).
IF the current item in the first array (ProductList[i]) is equal to (==) the current item in the second array (ProductValue[j]) THEN you will mark the option as selected.
Some useful tools for your JS needs:
google
W3Schools.com
Firebug (Firefox addon, though most browsers have something tied to F12 that can help, use it to see your variables and step through the functions)

Categories

Resources