How to prevent Javascript updating entire control, and refreshing content? - javascript

I have this code:
function addFormControls() {
var e = document.getElementById("ProductsList");
var prodid = e.options[e.selectedIndex].value;
var prodvalue = e.options[e.selectedIndex].text;
if (num == 0) {
document.getElementById("ProductsPanel").innerHTML = '<h3>Products added to Variant</h3>';
}
if (num < 10) {
var boolCheck = checkArrayData(prodid);
if (boolCheck == false) {
document.getElementById("ProductsPanel").innerHTML = document.getElementById("ProductsPanel").innerHTML + prodvalue + '<input type="text" id="' + prodid + 'product" value="0" width="50px" maxlenght="2" /><input type="button" onclick="updateArrayData(\'' + prodid + '\', document.getElementById(\'' + prodid + 'product\').value);" value="Update Number" /><br />';
num++;
prodIdArray.push({
'key': prodid,
'value': prodvalue,
'num': 0
});
document.getElementById("productsArray").value = prodIdArray;
} else {
alert("Sorry product has already been added!");
}
}
}
which happily updates a div tag with new info, however if you look at the section where it prints a text box to the screen, line 13, these textbox's will be updated by the user.
So in short, textboxs are added, and value update.
however if there is a textbox with value 5, then this function called again to add another textbox, the previous textbox' values will be wiped clean!
So, how do i prevent this, will i have to do some, for loop over div controls taking the values, then put them back after this function is called?!?

I create some javascript to save all the values in a particular input's value field before adding the control, then return all the saved values back to their respected inputs.
function saveValuesOfProducts()
{
// initialise the array
numOfProds = new Array();
// get all the elements which are inputs
var x=document.getElementsByTagName("input");
// remove all un necessary inputs
x = leaveTextInputs(x);
// loop through the entire list of inputs left saving their value
for (i=0; i<x.length; i++)
{
numOfProds.push(x[i].value);
}
}
function returnValuesOfProducts()
{
// get all the elements which are inputs
var x=document.getElementsByTagName("input");
// remove all un necessary inputs
x = leaveTextInputs(x);
// loop through the entire list of saved values and return them to the input
for (i=0; i<numOfProds.length; i++)
{
x[i].value = numOfProds[i];
}
}
function leaveTextInputs(value)
{
// create a new blank array
var newArr = new Array();
// loop through all the elements in passed array
for (i=0; i<value.length; i++)
{
// cache the element
var thevalue = value[i];
// check if the element is a text input
if (thevalue.type == "text")
{
// check the id consists of product in it!
var regexteststring = thevalue.id;
// create the pattern to match
var patt1 = /product/i;
if (regexteststring.match(patt1) == "product")
{
// as additional check, if it has a size quantity of 2 then its defo out stuff
if (thevalue.size == 2)
{
newArr.push(thevalue);
}
}
}
}
// now return the new array
return newArr;
}

Related

Saving a couple of strings in the local storage

I'm trying to save some strings in the local storage, I'm trying to do this but I get undefined in the local storage.
I'm asking the user for the players names, and then I want to store them in the local storage in order to use them again.
Here's what I'm trying :
const x = localStorage.getItem('playersNum');
const parentDiv = document.getElementById('player-list');
for (let i = 0; i < x; i++) {
const newInput = document.createElement("INPUT");
newInput.setAttribute("type", "text");
newInput.setAttribute("class", "form-control");
newInput.setAttribute("id", `player${i}`);
newInput.setAttribute("placeholder", "Player's Name");
parentDiv.appendChild(newInput);
}
//get all input elements of type text and starting id with player
const input = document.querySelectorAll("[type='text'][id^='player']");
const btn = document.getElementById('startGame');
btn.addEventListener('click', function() {
//reset border style of all input elements
[...input].forEach(el => el.style.border = '');
//get all empty input elements
let empty = [...input].filter(el => el.value.trim() == "");
//check length
if (empty.length) {
//show alert
// alert('Please fill in the players names');
//set border style to empty input elements
empty.forEach(el => el.style.border = '1px solid red');
}
else {
window.location.assign('game.html');
localStorage.setItem('playersNames', String(input.value));
}
});
You're declaring input with querySelectorAll, so you need to read input as an array.
localStorage.setItem('playersNames', String(input[0].value));
Then, if you want all player's names you will need to iterate through the array. Also, you need to get the previous value of localStorage and append to it, since it gets overwritten every time you set it.
const input = document.querySelectorAll("[type='text'][id^='player']");
for (i=0; i < input.length; i++) {
var checkForStorage = localStorage.getItem('playersNames');
if (checkForStorage !== null) {
localStorage.setItem('playersNames', checkForStorage + ',' + String(input[i].value))
} else {
localStorage.setItem('playersNames', String(input[i].value));
}
};

How to add a difficulty to a Javascript hangman game

I want to allow the user to select the difficulty of the game. Easy is words length 3-5, Medium is length 6-9, Hard is 10-15. The word is being pulled from an AJAX API. Also, I've consulted this example but am still struggling to apply it to my own. I included extra code because I'm not sure if I could add radio buttons that store the level and word.length that then updates the word retrieved from the api to be the correct length.
var api = 'https://hangman-api.lively.software';
//add alphabet to div
alphabet.forEach((i) => {
$('.hangman-letters').append(`<div id="letter-${i}">${i}</div>`);
});
//set up initial puzzle
newPuzzle();
//set up new puzzle when user clicks "start over"
$('#game-over-replay').click(function(){
newPuzzle();
});
//trigger game on clicking letter button
$('.hangman-letters div').click(function(){
submitLetter(this.innerHTML, this);
});
//trigger game on keypress
$(window).keypress(function(e){
var thisKey = String.fromCharCode(e.which);
if(alpha.indexOf(thisKey) > -1) {
submitLetter(thisKey, document.getElementById(`letter-${thisKey}`));
}
})
//functions
//handle clicked letter or keyboard input
function submitLetter(letter, thisLetterButton) {
var isCorrect = letterChosen(letter);
if(isCorrect) $(thisLetterButton).addClass('disabled correct');
else $(thisLetterButton).addClass('disabled');
if(remainingBlanks < 1) {
gameOver(true);
}
if(totalIncorrect >= hangmanParts.length + 1) {
gameOver(false);
}
}
//wipe variables and containers and set up new game
//now called after api call is complete
function setUp(){
$('.game-over').hide();
puzzleLetterContainers = [];
previouslyChosen = '';
totalIncorrect = 0;
remainingBlanks = puzzle.length;
$('.hangman-puzzle').html('');
$('#added-parts').html('');
$('.hangman-letters div').each(function(){
this.classList = '';
})
puzzle.split('').forEach((i) => {
var thisClass = "hangman-puzzle-letters",
placeholder = " ";
if(i == ' ' || i == '-') {
thisClass += ' space';
remainingBlanks--;
placeholder = i;
}
$('.hangman-puzzle').append(`<div class="${thisClass}">${placeholder}</div>`);
});
//var difficulty[] = new difficulty;
//var difficulty[1] = Easy;
//var difficulty[2] = Medium;
//var difficulty[3] = Hard;
puzzleLetterContainers = document.getElementsByClassName('hangman-puzzle-letters');
}

Changing DOM with Select Option and checking no of required fields

There is a webpage with certain number of required fields that needs to be filled in order to submit a form successfully.
The biggest indicator of required field is that it has a * and its label has a class 'required' in it.
The number of required fields change when we change dropdown value. I have written some javascript and jquery code that changes the dropdown value and then checks the number of required fields but for some reason(most probably DOM changes is taking time and code executes before that so actually the change in number of required fields is not reflected in page). However if I change the dropdown value manually and then run the checkRequired() function, it works fine but I want to automate the procedure. How can I achieve that?
var count = 0;
var allRequired = []; // total number of required fields in the page
var newRequired = []; // change in the no. of required fields
$('select').each(function(){
var id = $(this).attr('id');
$('#'+id+' option').each(function() {
$(this).attr('selected','selected');
if(count == 0){
getAllRequiredFields();
}
else{
setTimeout(() => {
checkRequired();
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',allRequired[index]);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}, 3000);
}
count++;
})
});
function getAllRequiredFields(){
$('span.required').each(function () {
var text = $(this).parent().text()
var id = $(this).closest("td").attr('id').split("_label")[0];
allRequired.push(id);
});
}
function checkRequired() {
newRequired = [];
$('span.required').each(function () {
var text = $(this).parent().text()
var id = $(this).closest("td").attr('id').split("_label")[0];
newRequired.push(id);
});
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',count);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}
Just added change event fixed my problem
$('#'+id+' option').each(function() {
$(this).attr('selected','selected');
$('#'+id).change();
if(count == 0){
getAllRequiredFields();
}
else{
setTimeout(() => {
checkRequired();
for (let index = 0; index < allRequired.length; index++) {
console.log('for else',allRequired[index]);
if(!newRequired.includes(allRequired[index])){
console.log('allRequired',allRequired[index]);
}
}
}, 3000);
}
count++;
})

Getting an infinite loop and can't see why - Javascript

I'm writing a simple little Connect 4 game and I'm running into an infinite loop on one of my functions:
var reds = 0;
var greens = 0;
function checkEmpty(div) {
var empty = false;
var clicked = $(div).attr('id');
console.log(clicked);
var idnum = parseInt(clicked.substr(6));
while (idnum < 43) {
idnum = idnum + 7;
}
console.log("idnum=" + idnum);
while (empty == false) {
for (var i = idnum; i > 0; i - 7) {
idnumStr = idnum.toString();
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
}
}
return divToFill;
}
function addDisc(div) {
if (reds > greens) {
$(div).addClass('green');
greens++;
console.log("greens=" + greens);
} else {
$(div).addClass('red');
reds++;
console.log("reds=" + reds);
};
$(div).removeClass('empty');
}
$(function() {
var i = 1;
//add a numbered id to every game square
$('.game-square').each(function() {
$(this).attr('id', 'square' + i);
i++;
//add an on click event handler to every game square
//onclick functions
$(this).on('click', function() {
var divToFill = checkEmpty(this);
addDisc(divToFill);
})
})
})
Here is a link to the codepen http://codepen.io/Gobias___/pen/xOwNOd
If you click on one of the circles and watch the browser's console, you'll see that it returns true over 3000 times. I can't figure out what I've done that makes it do that. I want the code to stop as soon as it returns empty = true. empty starts out false because I only want the code to run on divs that do not already have class .green or .red.
Where am I going wrong here?
for (var i = idnum; i > 0; i - 7);
You do not change the i.
Do you want to decrement it by 7?
Change your for loop to the one shown below:
for (var i = idnum; i > 0; i -= 7) {
// ...
}
You also do not use loop variable in the loop body. Instead, you use idnum, I think this can be issue.
while (empty == false) {
for (var i = idnum; i > 0; i -= 7) {
idnumStr = i.toString(); // changed to i
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
// and don't forget to stop, when found empty
if (empty) break;
}
}
I add break if empty found, because if we go to next iteration we will override empty variable with smallest i related value.
You can also wrap empty assignment with if (!empty) {empty = ...;} to prevent this override, but I assume you can just break, because:
I want the code to stop as soon as it returns empty = true
Offtop hint:
while (idnum < 43) {
idnum = idnum + 7;
}
can be easy replaced with: idnum = 42 + (idnum%7 || 7)
Change to this:
for (var i = idnum; i > 0; i = i - 7) {
You are not decrementing the i in your for loop
Building on what the others have posted You would want to change the value of empty inside the for loop. because obviously the string still checks the last string in the loop which would always return false.
while(empty==false){
for (var i = idnum; i > 0; i -= 7) {
// your other codes
if (!empty) {
empty = str.includes('empty');
}
}

How to Increase the numurical value of 3rd column in a particular row when some one click on the link which is in the 2nd column of same row

How to increase the numerical value of 3rd column in a particular row when some one click on the link which is in the 2nd column of same row? Data loads from firebase in tabular form.
Fiddle here, so you can understand it much better.
The script which loads (callback) data from firebase is given bellow
var LEADERBOARD_SIZE = 10;
var get_title = $('title').html();
var get_id = $('id').find('textarea').html();
// Create our Firebase reference
var scoreListRef = new Firebase('https://androidappania.firebaseio.com//AlternateLinksDirectory//' + get_id);
// Keep a mapping of firebase locations to HTML elements, so we can move / remove elements as necessary.
var htmlForPath = {};
// Helper function that takes a new score snapshot and adds an appropriate row to our leaderboard table.
function handleScoreAdded(scoreSnapshot, prevScoreName) {
var newScoreRow = $("");
newScoreRow.append($("").append($("").text(scoreSnapshot.val().name)));
newScoreRow.append($("").text(scoreSnapshot.val().url));
newScoreRow.append($("").text(scoreSnapshot.val().score));
// Store a reference to the table row so we can get it again later.
htmlForPath[scoreSnapshot.name()] = newScoreRow;
// Insert the new score in the appropriate place in the table.
if (prevScoreName === null) {
$("#leaderboardTable").append(newScoreRow);
} else {
var lowerScoreRow = htmlForPath[prevScoreName];
lowerScoreRow.before(newScoreRow);
}
}
// Helper function to handle a score object being removed; just removes the corresponding table row.
function handleScoreRemoved(scoreSnapshot) {
var removedScoreRow = htmlForPath[scoreSnapshot.name()];
removedScoreRow.remove();
delete htmlForPath[scoreSnapshot.name()];
}
// Create a view to only receive callbacks for the last LEADERBOARD_SIZE scores
var scoreListView = scoreListRef.limit(LEADERBOARD_SIZE);
// Add a callback to handle when a new score is added.
scoreListView.on('child_added', function (newScoreSnapshot, prevScoreName) {
handleScoreAdded(newScoreSnapshot, prevScoreName);
});
// Add a callback to handle when a score is removed
scoreListView.on('child_removed', function (oldScoreSnapshot) {
handleScoreRemoved(oldScoreSnapshot);
});
// Add a callback to handle when a score changes or moves positions.
var changedCallback = function (scoreSnapshot, prevScoreName) {
handleScoreRemoved(scoreSnapshot);
handleScoreAdded(scoreSnapshot, prevScoreName);
};
scoreListView.on('child_moved', changedCallback);
scoreListView.on('child_changed', changedCallback);
// When the user presses enter on scoreInput, add the score, and update the highest score.
$("#scoreInput").keypress(function (e) {
if (e.keyCode == 13) {
var newScore = ($("#scoreInput").val());
var url1 = $("#urlInput").val();
var name = $("#nameInput").val();
$("#scoreInput").val("");
if (url1.length === 0)
if (name.length === 0) return;
var userScoreRef = scoreListRef.child(name);
// Use setWithPriority to put the name / score in Firebase, and set the priority to be the score.
userScoreRef.setWithPriority({
name: name,
url: url1,
score: newScore
}, newScore);
alert('Alternate Link for this App has been Succesfully submitted by you. By using this service you agree that you will Not Spam or Submit Links which refers to illegal or Copyrighted content.');
}
});
// delay function to make link clickable after 4 sec and also add onclick='HitCounter()' into links
var delay = 4000 //4 seconds
setTimeout(function () {
function replaceURLWithHTMLLinks(text) {
var re = /(\(.*?)?\b((?:https?|ftp|file):\/\/[-a-z0-9+&##\/%?=~_()|!:,.;]*[-a-z0-9+&##\/%=~_()|])/ig;
return text.replace(re, function (match, lParens, url) {
var rParens = '';
lParens = lParens || '';
var lParenCounter = /\(/g;
while (lParenCounter.exec(lParens)) {
var m;
if (m = /(.*)(\.\).*)/.exec(url) || /(.*)(\).*)/.exec(url)) {
url = m[1];
rParens = m[2] + rParens;
}
}
return lParens + "" + url + "" + rParens;
});
}
var elm = document.getElementById('leaderboardTable');
elm.innerHTML = replaceURLWithHTMLLinks(elm.innerHTML);
$(document).ready(function () {
$("a[href^='http://']").filter(function () {
return this.hostname && this.hostname !== location.hostname;
}).attr('target', '_blank');
});
}, delay)
and the script which take care of URL Hit Counts is given bellow
function HitCounter() {
var get_id = $('id').find('textarea').html();
var HitCounterRef = new Firebase('https://androidappania.firebaseio.com//AlternateLinksDirectory//' + get_id);
var hits = $(tbody).find('tr').children('td').html();
if (hits == null) {
hits = 1;
} else {
hits++;
}
HitCounterRef.setWithPriority({
score: hits
}, hits);
};
I need some modification or improvement in this code so that when some one click on a link then correct corresponding 3rd column of same row should get a increment/increase in it's numerical value.
I also need something which could create connection b/w HitCounter and urls given in 2nd column of every row or initiate the HitCounter function when some one click on any of the link given in 2nd column of every row.

Categories

Resources