Function is repeating same values multiple times - javascript

I am writing some javascript code to create a flashcard system. In this system, a flashcard is displayed to the user and he decides whether the card is difficult or easy. In this way, each card is sorted into two different groups that will be used later. For the following code, arr is the flashcard list while the difficultList and easyList are the two lists. I have also used jquery to run a function according to the class. So, if the button with difficult flashcard is clicked, difficultList is changed. Do note that as of now, the end() function simply logs 'END' to the console. Finally, the text variable used in nothing but an HTML element with id of text whose value is changed to display the question.
function mainFunc() {
if (indexVal > arr.length) {
end();
} else {
console.log(indexVal);
text.innerHTML = arr[indexVal][0];
$(".difficult").click(function () {
indexVal += 1;
difficultList.push(arr[indexVal]);
mainFunc();
})
$(".easy").click(function () {
indexVal += 1;
mainFunc();
easyList.push(arr[indexVal]);
})
}
}
mainFunc();
When the code runs for the first time, everything works fine. But when I click on any of the buttons during second flashcard, an error occurs and the value of indexVal increases by 2 instead of 1, causing some unexpected behaviour. I have made several attempts in debugging the code but to no avail. Any help would be greatly appreciated (the problem with the code, a new solution etc). Thank you!

Related

A way to add parameters to variables or something so I don't spam functions and vars

So the point of this, game like, website JavaScript is creating triggers. The Const pgUnlock is the on and off switch. I want it so that when the viewer clicks on a button, I will change the element to turn the false into a true. For example, below, it checks if the number 1 is in the [0] index and if it is, it'll unlock a new part of the website, by replacing the # with the next page link. The function 'alertbox()' checks this and if the trigger isn't on, it'll make a button visible, letting the player know that the "page is locked". So my question is how do I add parameters to consolidate the code so I'm not creating 5 more 'alertbox()' functions because the 'check' var has to be customized for each placement for 'pgUnlock'. If not, I'm fine with repeating the code, I just want to see if I/we can keep everything performance friendly by using cleaner code, as I'm not that familiar with JavaScript. To let you know how dumb I am, one of my tries was: 'var check(x,y)= pgUnlock.includes(x,y);'
var a = document.querySelector('.rebtn[href="#"]');
const pgUnlock= [0,0,0,0,0];
var check= pgUnlock.includes(1,0);
var check2= pgUnlock.includes(2,0);
var check3= pgUnlock.includes(3,0);
var check4= pgUnlock.includes(4,0);
var check5= pgUnlock.includes(5,0);
if (check==true) {
a.setAttribute('href', './introPage.html');
}
reBtn.onclick=()=>{
alertbox();
}
legBtn.onclick=()=>{
alertbox();
}
godBtn.onclick=()=>{
alertbox();
}
chgBtn.onclick=()=>{
alertbox();
}
ch2Btn.onclick=()=>{
alertbox();
}
function alertbox(){
if(check==false){
alertBtn.classList.add("visalert");
}
}

Run several small test within one 'it' in E2E test using Protractor

I am working on a E2E test for a single-page web application in Angular2.
There are lots of clickable tags (not redirected to other pages but has some css effect when clicking) on the page, with some logic between them. What I am trying to do is,
randomly click a tag,
check to see the the response from the page is correct or not (need to grab many components from the web to do this),
then unclick it.
I set two const as totalRound and ITER, which I would load the webpage totalRound times, then within each loading page, I would randomly choose and click button ITER times.
My code structure is like:
let totalRound: number = 10;
let ITER: number = 100;
describe('XX Test', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
describe('Simulate User\'s Click & Unclick',() => {
for(let round = 0; round < totalRound; round++){
it('Click Simulation Round ' + round, () =>{
page.navigateTo('');
let allTagFinder = element.all(by.css('someCSS'));
allTagFinder.getText().then(function(tags){
let isMatched: boolean = True;
let innerTurn = 0;
for(let i = 0; i < ITER; i++){
/* Randomly select a button from allTagFinder,
using async func. eg. getText() to get more info
about the page, then check if the logic is correct or not.
If not correct, set isMatchTemp, a local variable to False*/
isMatched = isMatched && isMatchTemp;
innerTurn += 1;
if(innerTurn == ITER - 1){
expect(isMatched).toEqual(true);
}
}
});
});
}
});
});
I want to get a result after every ITER button checks from a loading page. Inside the for loop, the code is nested for async functions like getText(), etc..
In most time, the code performs correctly (looks the button checkings are in sequential). But still sometimes, it seems 2 iterations' information were conflicted. I guess there is some problem with my code structure for the async.
I thought JS is single-thread. (didn't take OS, correct me if wrong) So in the for loop, after all async. function finish initialization, all nested async. function (one for each loop) still has to run one by one, as what I wish? So in the most, the code still perform as what I hope?
I tried to add a lock in the for loop,
like:
while(i > innerTurn){
;
}
I wish this could force the loop to be run sequentially. So for the async. func from index 1 to ITER-1, it has to wait the first async. finish its work and increment the innerTurn by 1. But it just cannot even get the first async. (i=0) back...
Finally I used promise to solve the problem.
Basically, I put every small sync/async function into separate promises then use chaining to make sure the later function will only be called after the previous was resolved.
For the ITER for loop problem, I used a recursion plus promise approach:
var clickTest = function(prefix, numLeft, ITER, tagList, tagGsLen){
if(numLeft == 0){
return Promise.resolve();
}
return singleClickTest(prefix, numLeft, ITER, tagList, tagGsLen).then(function(){
clickTest(prefix, numLeft - 1, ITER, tagList, tagGsLen);
}).catch((hasError) => { expect(hasError).toEqual(false); });
}
So, each single clicking test will return a resolve signal when finished. Only then, the next round will be run, and the numLeft will decrease by 1. The whole test will end when numLeft gets to 0.
Also, I tried to use Python to rewrite the whole program. It seems the code can run in sequential easily. I didn't met the problems in Protractor and everything works for my first try. The application I need to test has a relatively simple logic so native Selenium seemed to be a better choice for me since it does not require to run with Frond-end code(just visit the webapp url and grab data and do process) and I am more confident with Python.

Problems with flipping cards (vanilla JS)

I'm trying to solve 2 problems with this project:
Flip the cards back when no match is made.
Once the randomization occurs, allow the user to briefly show all the randomized cards for x seconds before the game timer commences.
At one point I was able to flip the unmatched cards, but I lost that ability whilst trying to sort out problem #2.
For #1 I first declared a variable:
const pix = document.querySelectorAll('.card img');
Then I did an if/else to hide unmatched:
function checkForMatch() {
if (
toggledCards[0].firstElementChild.className === toggledCards[1].firstElementChild.className) {
toggledCards[0].classList.toggle('match');
toggledCards[1].classList.toggle('match');
toggledCards = [];
matched++;
} else {
setTimeout(() => {
toggleCard(toggledCards[0]);
toggleCard(toggledCards[1]);
toggledCards = [];
// Trying to hide unmatchaed cards here
pix.style.display = "none";
}, 1000);
}
};
That fails and I cannot figure out why.
As Sheng Slogar have mentioned, You don't have class names on your img tags so it doesn't work. I added some to check and it was working, so just add classes with numbers to images and it will work properly :)
I also recommend to use data attributes for this kind of functionality as it's exactly what they are made for.

Reset counter variable on condition

I have this simple "pagination" counter which is fetching the next page from an API. It works fine but the problem is that whenever I change category (movies or series) the counter obviously doesn't reset so instead of fetching the first page of the new category it continues from the number it left off.
I tried numerous conditional combinations but nothing really worked so far. I'm sure it's not that hard to solve I just can't think of the right logic to use.
let page = 1;
document.getElementById('load-more').addEventListener('click', () => {
page++;
const movies = document.getElementById('movies');
const series = document.getElementById('series');
if(movies.classList.contains('active-link')) {
getMovies(page);
} else if (series.classList.contains('active-link')) {
getSeries(page);
}
})
Reseting the let counter inside the if..else doesn't really work because every time I click the load more button it resets it back to page 1.
Use separate variables for the current movies page and the current series page. Also note that you can simplify your logic by using a single querySelector instead of selections followed by classList.contains:
let moviesPage = 1;
let seriesPage = 1;
document.getElementById('load-more').addEventListener('click', () => {
if (document.querySelector('#movies.active-link')) {
moviesPage++;
getMovies(moviesPage);
} else if (document.querySelector('#series.active-link')) {
seriesPage++;
getSeries(seriesPage);
}
});
Set another event listener for the click on your #movies and #series link,
and set the page variable to 1 at this place.
That would be the usual behavior when switching lists, one usually see a reset of paging.

Why is this onClick event not being applied correctly?

I'm using late-binding to assign onClick events to checkboxes (styled as dots). My first assignment [located at https://github.com/farfromunique/vampirrePoints/blob/master/events.js#L264 ] goes perfectly, and reacts as expected - all dots have this as their onClick:
/* https://github.com/farfromunique/vampirrePoints/blob/master/main.js#L440 */
allDots[i].onclick = function() {
if (this.checked) {
decrementCounter(1);
} else {
incrementCounter(1);
};
}
However, when Step11() is triggered, and freebieDotSetup() is called, only some of the checkboxes get their onClicks updated. Specifically, sta1, sta2, sta3, sta4, sta5 (possibly others, too) keep their initial value.
I have tried putting console.log() statements in during the assignment process, and it looks like the assignment happens, but it doesn't "stick". Why doesn't this work?
Code reference (whole site): https://github.com/farfromunique/vampirrePoints
By request, a non-working JSFiddle: http://jsfiddle.net/farfromunique/mS4Lp/
Note: the menu is on the wrong side, doesn't advance properly, and none of the "dots" (checkboxes) are clickable, so functionality is not testable. I strongly suspect that my code is not cross-browser compatible, but that isn't a priority for me (yet).
The solution: In the function freebieDotSetup(), I was doing this:
for (i=0;i<attributeDots.length;i++) {
attributeDots[i] = allDots[i];
}
...
for (i=0;i<abilityDots.length;i++) {
abilityDots[i] = allDots[i+attributeDots.length];
}
...
for (i=0;i<disciplineDots.length;i++) {
disciplineDots[i] = allDots[i+abilityDots.length];
}
...
Since I was using the previous group's length, it would occasionally overwrite the previous values (due to groups being shorter). I corrected this with this:
startPos = startPos + attributeDots.length;
for (i=0;i<abilityDots.length;i++) {
abilityDots[i] = allDots[i+startPos];
}
Adding the previous group's length to startPos each time. Making this change resolved my issue.
... But the JSFiddle is totally busted, still.

Categories

Resources