On some devices, Javascript assigns new text nodes only after second selection - javascript

I wrote a simple website, which displays 1 of 150 Psalms at random with a random image from a small array of images. Once loaded user gets two choices, either read another Psalm at random (button "Any Psalm") or choose one themselves (select element). The function that loads a random Psalm works fine, but the select button, though works fine on local server and also on my laptop after pushing it to Github, but on my phone and iPad it works only if you select again, so say you're on Psalm 20, then you select Psalm 83 and then nothing happens, until you select again, say psalm 102, only then that it loads psalm 83, so you're always one step behind.
I suspect it may have nothing to do with the code, nonetheless, here's my function;
const selectPsalm = () => {
loadingImage();
let psalms = randomPsalm(psalmsBulk)[1];
let selectedPsalmIndex = document.getElementById("choose").value;
let lastIndex = () => {
if(psalms.indexOf(psalms[selectedPsalmIndex])<10) {
return 2
} else if(psalms.indexOf(psalms[selectedPsalmIndex])<100) {
return 3
} else return 4
}
strHeading = psalms[selectedPsalmIndex].slice(0, psalms[selectedPsalmIndex].indexOf(psalms.indexOf(psalms[selectedPsalmIndex]))+lastIndex());
strScripture = psalms[selectedPsalmIndex].slice(psalms[selectedPsalmIndex].indexOf(psalms.indexOf(psalms[selectedPsalmIndex]))+lastIndex());
document.getElementById('heading').innerHTML = strHeading;
document.getElementById('psalm').innerHTML = strScripture;
}```
and these are my event listeners:
//document.getElementById("random").addEventListener('click', newRandomPsalm);
//document.getElementById("choose").addEventListener('click', selectPsalm);
$('document').ready(function(){
$('#random').on('click', newRandomPsalm);
$('#choose').on('click', selectPsalm)
})
I commented out my original js event listeners and changed them for jQuery ones, because I am learning jQuery and wanted to see it in my code, but both sets of statements do exactly the same.
You can see it in action at:
https://psalms.live/
My question is; what is wrong and how to fix it?

it turns out that on('click') is not always suitable for select dropdown element. The correct syntax is on('change').

Related

A random pair of audio tags from an array are played when the user clicks a button. How to generate a new pair with a click of a different button? JS

I am making a website where the user can practise their recognition of musical intervals within a range of one octave.
Upon loading, the page randomly selects two notes (audio tags) from an array of 13. There is a large button on the page, that, when pressed, plays the two randomly selected notes.
After identifying the interval, the user should press submit to check their answer and they will be alerted if they are right or wrong.
My goal is that after pressing "submit", a new pair of randomly selected notes will be generated without having to refresh the page. However, I have so far only been able to achieve either always having the same pair of notes, or else having a new random pair of notes being generated every single time the user presses the big button, even if they have not submitted their answer yet.
Here is some of the code I have so far - I've tried to remove as much as possible not relevant to the problem.
intervalButton is the "big button".
const intervalButton = document.getElementById("quaver-button");
const notes = document.getElementsByTagName("audio");
const notesArray = Array.from(notes);
let randomNote = notesArray[Math.floor(Math.random() * notesArray.length)];
let randomNoteTwo = notesArray[Math.floor(Math.random() * notesArray.length)];
const submitButton = document.getElementById("submit");
intervalButton.addEventListener("click", function() {
randomNote.play();
setTimeout(function () {
randomNoteTwo.play()
}, 1000);
})
submitButton.addEventListener("click", function() {
if (code for if user gets answer right) {
alert("Correct message");
} else {
alert("Not correct message");
}
})
So far I have tried removing my declarations for the variables holding the random notes, and then defining a function to get the random notes instead. I called this function in an event listener when the user clicks the big button, but of course this generates new random notes with every click.
I have also tried redeclaring the random notes in the submit button event listener listed above like so:
submitButton.addEventListener("click", function() {
if (code for if user gets answer right) {
alert("Correct message");
let randomNote = notesArray[Math.floor(Math.random() * notesArray.length)];
let randomNoteTwo = notesArray[Math.floor(Math.random() * notesArray.length)];
} else {
alert("Not correct message");
}
})
This still gives me only the two initially generated random notes.
I have tried using my function that gets the random notes in this block too.
I have a fair idea that my problem has something to do with where I am declaring the variables, but so far I am really stuck with this.
Hope this question is acceptable - I got slated (fairly) for my last one but am brand spanking new to all this. Just a few weeks in with JS.

WebDriverIO browser.Click couldn't find element in Chrome and Running fine in Firefox

I am using WebdriverIO with CucumberJS to do testing.
The code below works fine in Firefox, but I'm getting errors in Chrome, shows element is not clickable. I am looking for solution in JavaScript.
this.Then('I click on View Coupon Details button on a random coupon', () => {
const randomElement = getRandomIndex(couponsCount);
assert.ok(coupons.value[randomElement].element('.print-coupon').click('a'));
});
coupons is an array of WebElements. I am trying to click on View Coupon detail button.
Sample Page:
http://www.princefrederickdodge.com/coupons.htm
Thanks,
Vinod
Try use an browser pause before your code
browser.pause(2000);
Sometimes this happens because of chrome delay. Always it works for me.
More: http://webdriver.io/api/utility/pause.html
In the first way you can copy 99% the xpath/css selector from the inspector and .click will always work then. If not there 2 alternatives
If you run scripts localhost and you have access you can do
.execute(function(a, b, c, d) {
$('#button').click();
return a + b + c + d;
}, 1, 2, 3, 4).then(function(ret) {
// node.js context - client and console are available
log(ret.value); // outputs: 10
});
or with this way. the mouse will be pressed and release. You can find the right place if you make rightclick with webdriver.io to know where your coordinates are.
.moveToObject('#button', 0, -103)
.buttonDown()
.moveToObject('#button', 0, -104)
.buttonUp()
Not sure if there are better ways to do this, I am using, getLocation() and scroll to the location of the button to make it visible in viewport and then click it.
this.Then('I click on View Coupon Details button on a random coupon', () => {
const randomElement = getRandomIndex(couponsCount);
const pos = coupons.value[randomElement].getLocation();
browser.scroll(pos.x, pos.y);
browser.pause(200); // we can use waitforVisible .print-coupon as well
assert.ok(coupons.value[randomElement].element('.print-coupon').click('a'));
});

Volume for sound not consistent when calling string from localStorage

I have a function that is behaving in a way that i do not like, and i cannot identify why. The overall function works fine, and when the volume is changed using the range element somewhere else in the interface, that works too. But lets say if I set the object in localStorage to "0.6" it will play at the right volume, BUT every so often it behaves as if the volume is "1" or default(i think). I sent the variable to my console to see what it says and it behaves like there is nothing wrong. The audio still sometimes gives me default volume even though the console says it's the right number stored in LS.
Here is the JS to the function that fires my biting sound:
biteFunc: function () {
var snd, myAu;
myAu = localStorage.getItem("Au");
//the user uses a range input to set this value, works fine
snd = new Audio("../Audio/bite.wav");
//the file in the location i want it to be, works fine
if (!myAu || myAu === "0") {
return false;
//if the user sets the sound to "0", the function will not fire
}
if (myAu) {
snd.volume = myAu;
snd.play();
/*this works and the console shows that each time the sound is fired,
the correct volume is there. But sometimes(especially when tapping
the button quickly) the volume behaves like its default or "1"
even though the object console says the right volume
*/
}
}
-Could my function be firing without reading the volume and spitting out the default volume when that happens?
-I thought it to be a timeline issue so I set the volume inside of the conditional that detects myAu, still nothing.

How to prevent users from affecting number of button clicked times

I have a game written in JavaScript and what it basically does is start a ten seconds timer and register the number of times the user is able to click on a certain button, before the timer elapses.
How the code works:
When a user clicks on the button, an element gets added to an array, using push function, then a different function returns the length of the array as the number of times clicked.
The problem with this:
If a user opens up the dev tools and alters the number of times an element is added to the array per click, this will change the outcome of the result.
My Approach:
What I decided to do is to store the length before I ran the push function and also after I ran the push function, then compare their differences and if it's greater than 1, it means something is not right. This seemed to work in my head until I wrote it down in code and discovered that if the user pushed multiple times before I checked the differences then it would go unnoticed. Please big brained guys, help me.
My code:
$('body').on('click', '.btn.z', function () {
// start listening
startCountingClicks()
})
var timerStarted = false;
var tc = [];
function startCountingClicks () {
$('.btn.z').html('ClickZed');
$('.Score').html('Your Score: '+gettc()+" clicks");
if (timerStarted == false) {
startTimer(10, $('#time'));
}
// user does multiple push before this function: startCountingClicks is called
var previous_length = tc.length; // get length before push
tc.push(1);
var new_length = tc.length; // get length after push
if (new_length - previous_length !== 1) {
console.log("fraud"); // this is supposed to catch a thief!!!
}
console.log(new_length+" "+previous_length);
timerStarted = true;
}
function gettc (){
// get number of clicks
return tc.length ;
}
A code that totally breaks this:
$('button').click(function(){tc.push(1); tc.push(1)})
EDIT:
I do not wish to protect against dev tools, though I am not against that method if it works. I just wish to get a better way of counting my clicks, a way that can't be affected by writing code on the dev tools.
You can't really stop people from doing stuff on the client side. It is pointless trying to prevent that. The best thing you can do is make sure whatever is sent matches what you expect on the server side.

Keep creating an extra empty page on "next"

I have a problem with a tool built in HTML and Angular.js.
Basically the site is built the way that it should store 15 entries on a page, then you press "Next" and the next 15 entries should be listed, which works fine.
BUT, when you are at the last page (when there is no more entries) it automatically creates another "Next page" which is empty.
I am a newbie on Angular.js and i am stuck right now.
$scope.loadCharters = function () {
var keys = [];
_.each($scope.sessions, function (sess) {
sess.checked && keys.push(sess.key);
});
charterFactory.getChartersBySession(keys, function (charters) {
$scope.charters = charters;
$scope.filterCharters();
}, 15, ($scope.page - 1) * 15);
};
$scope.nextPage = function () {
if ($scope.charters && $scope.charters.length) {
$scope.page++;
$scope.loadCharters();
}
};
This is the functions that should list the pages (15 entries / page). But i dont understand why it keeps creating +1 empty?
Any help would be appriciated.
There will be a html template somewhere that has an element with the attribute:
ng-click="nextPage()"
on it to capture the click. You need to add another attribute to that element that looks like:
ng-disabled="page*15 >= charters.length"
this should disable the element from being clicked when you're on the last page.

Categories

Resources