I have repeated JS code, how do I turns these into functions - javascript

Here is the JSFiddle link for my project, you can see the full app.js here... https://jsfiddle.net/be4pLh7s/1/
Basically I am trying to build a contact diary where you can create new contacts and then be able to edit or delete them at a later stage...
on line 85 onwards is the click event for the Edit and Delete buttons, I THINK that the way I have written this part of the code maybe incorrect because I have repeated loops and if statements.
I have tried putting these repeated parts of the code into functions but then the app crashes and I receive different errors. I have tried a couple of things to overcome these errors but still cant get it to work and or get my head around this.
Please could you advise if the code is correct... have I repeated myself? If I have then please can you show/tell me how to make this code better in terms of DRY, and readability. Thank you.
How do I code separate functions for the "Edit", "Save" and "Delete" buttons.
This line of code is repeated 3 times -
for (var i = 0; i < contactsBook.length; i++) {
if (contactsBook[i].firstName === ul.getAttribute('data-person')) {}
This line of code is repeated 2 times -
const ulChild = ul.childNodes;
for (var j = 0; j < ulChild.length; j++) {
if (ulChild[j].tagName === "LI") {}
Here is the part of the code in question -
//Click event for Edit and Delete buttons.
contacts.addEventListener("click", (e) => {
if (e.target.tagName === "BUTTON") {
const button = e.target;
const ul = button.parentNode;
if (button.textContent === "Edit") {
for (var i = 0; i < contactsBook.length; i++) {
if (contactsBook[i].firstName === ul.getAttribute('data-person')) {
const ulChild = ul.childNodes;
for (var j = 0; j < ulChild.length; j++) {
if (ulChild[j].tagName === "LI") {
const items = ulChild[j];
const input = document.createElement('input');
input.type = 'text';
input.value = items.textContent;
items.textContent = "";
items.insertBefore(input, ulChild.childNodes);
button.textContent = 'Save';
};
};
};
};
} else if (button.textContent === "Save") {
for (var i = 0; i < contactsBook.length; i++) {
if (contactsBook[i].firstName === ul.getAttribute('data-person')) {
const ulChild = ul.childNodes;
for (var j = 0; j < ulChild.length; j++) {
if (ulChild[j].tagName === "LI") {
console.log(ulChild[j]);
};
};
};
};
} else if (button.textContent === "Delete") {
contacts.removeChild(ul);
for (var i = 0; i < contactsBook.length; i++) {
if (contactsBook[i].firstName === ul.getAttribute('data-person')) {
contactsBook.splice(i,1);
localStorage.setItem('addbook', JSON.stringify(contactsBook));
};
};
};
};
});
Thank you for your help!

Not much of repeated code. Only hint I could give is if you want to use more javascrpt flare, e.g. .forEach instead of standard for loop and .filter since you have a for and if statement.
For an example
for (var i = 0; i < contactsBook.length; i++) {
if (contactsBook[i].firstName === ul.getAttribute('data-person'))
....
Can be done with:
contactsBook.filter(book => book.firstName === ul.getAttribute('data-person'))
Not that it makes any difference.

Related

Javascript Hangman Game Running Functions += Times After Reset

Ok this is my very first ever coding project. I'm self taught and thought creating a hangman game my 2 young kiddos could enjoy would be fun.
I have the game coded and it runs perfectly fine the first time through however, once I click on my reset button to restart the game, my lives start going down by 2 instead of one. After a third reset it goes down by three, and so on. Any console.log()s I put in to check run as many times as well.
I've spend hours racking my brain trying to figure it out and I've looked all over and I'm just not getting what's wrong. I thought about just saying screw it and resort to refreshing the page after every play through to avoid the problem but my brain wont let me do that.
Does anyone have any idea how to fix the problem? I know my code is probably not the most efficient and can definitely use to touch ups, but like I said, this is my first ever project and I know efficiency and skill will come with time and practice (like this). Below is the main chunk of my code.
function gameStart() {
// user writes in a word
pickedWord = prompt('pick a word').toUpperCase();
pickLetterHeading.innerText = 'Pick a Letter'
numLivesSec.hidden = false;
startBtn.disabled = true;
gameIsGoing = true;
resetBtn.disabled = false;
// enables buttons to press
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = false;
}
numLives = 7;
numLivesRemaining.innerText = numLives;
// calls the main game function
gameInProgress();
}
function reset() {
startBtn.disabled = false;
pickedWord = '';
gameIsGoing = false;
resetBtn.disabled = true;
pickLetterHeading.hidden = true;
numLivesSec.hidden = true;
while (guessedSec.firstChild) {
guessedSec.removeChild(guessedSec.firstChild);
}
for (let l = 0; l < alphabet.length; l++) {
document.getElementsByClassName('letterBtnClass')[l].disabled = true;
letters[l].classList.replace('correct', 'letterBtnClass');
letters[l].classList.replace('incorrect', 'letterBtnClass');
}
numLives = 7;
}
function gameInProgress() {
pickLetterHeading.hidden = false;
wordInProgress = '';
for (let i = 0; i < pickedWord.length; i++) {
let lettersToGuess = document.createElement('span');
lettersToGuess.innerText = '_';
guessedSec.appendChild(lettersToGuess);
wordInProgress += '_';
}
for (let btn = 0; btn < letters.length; btn++) {
letters[btn].addEventListener('click', function (e) {
letters[btn].disabled = true;
if (pickedWord.indexOf(letters[btn].innerText) == -1) {
console.log('letter not there!');
numLives -= 1;
numLivesRemaining.innerText = numLives;
console.log('TESTING!')
// checks if you have any tries left. If you have 0, then runs game over
if (numLives == 0) {
console.log('GAME OVER!')
gameIsGoing = false;
pickLetterHeading.innerText = 'You lose. Try again.'
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = true;
}
}
}
// checks if the letter picked matches anything in the chosen word
for (let x = 0; x < pickedWord.length; x++) {
if (letters[btn].innerText == pickedWord[x]) {
// adds class to chosen letter to show you guess correctly
letters[btn].classList.add('correct');
document.getElementsByTagName('span')[x].innerText = pickedWord[x];
wordInProgress[x] = pickedWord[x];
// if picked letter matches something in the chosen word, changes the "_" to the correct letter to show user progress
String.prototype.replaceAt = function (index, char) {
let a = this.split("");
a[index] = char;
return a.join("");
}
wordInProgress = wordInProgress.replaceAt(x, pickedWord[x]);
// when the word is complete. will show you win
if (wordInProgress == pickedWord) {
console.log("WINNER WINNER CHICKEN DINNER!");
pickLetterHeading.innerText = 'YOU WIN!'
for (let j = 0; j < alphabet.length; j++) {
document.getElementsByClassName('letterBtnClass')[j].disabled = true;
}
}
} else {
// since you chose incorrectly it adds a class to the button to show a bad choice
letters[btn].classList.add('incorrect');
}
}
})
}
}

Is there a way to get the Complete String using a portion of it using JavaScript?

In a GridView, the name of the table is getting generated dynamically. but it will have the dynamic Name with GridView ID gets appended.
something Like "w123443dsfnsbd32dkkd_GridView1". so first part will always keep changing whenever we reloads the grid. so I would like to get the name of the Grid with "_GridView1", with this I would like to fetch the complete Grid Name. So Is there a way to look for this?
I tried this var table = document.getElementById("GridView1"); but didn't work.
Code:
var table = document.getElementById("wcwidget_df5339c463eedb_widget_gridView1");
if (table.rows.length > 0) {
for (var i = 0 ; i < table.rows.length; ++i) {
if (table.rows[i].cells[0].innerText == "Company1" || table.rows[i].cells[0].innerText == "Company2" ||
table.rows[i].cells[0].innerText == "Company5" )
{
for (var k = 1; k < table.rows[i].cells.length; ++k) {
table.rows[i].cells[k].style.fontWeight = "bold";
table.rows[i].cells[k].style.color = "black";
}
}
}
for (var i = 0 ; i < table.rows.length; ++i) {
if (table.rows[i].cells[0].innerText == "Risk" || table.rows[i].cells[0].innerText == "Medium Risk" || table.rows[i].cells[0].innerText == "High Risk" ) {
table.rows[i].cells[0].style.fontWeight = "bold";
table.rows[i].cells[0].style.color = "black";
}
}
}
try this:
document.querySelectorAll("[id*='GridView1']")
this will return an array.
On modern browsers see the #amit's answer.
If compatibility with older browsers is required:
var allElements = document.getElementsByTagName("*");
for (var i = 0, n = allElements.length; i < n; ++i) {
var element = allElements[i];
if (element.id.endsWith("_GridView1")) {
// do something with the found element
break;
}
}

Making blocks visible/invisible using javascript

Here is my code.
var i = 0;
var submenues = document.getElementsByClassName("submenu");
var click = 1;
function submenuvisible() {
if (click == 1) {
for (i; i < submenues.length; i++) {
submenues[i].style.display = "block";
}
click = 2;
return;
}
if (click == 2) {
for (i; i < submenues.length; i++) {
submenues[i].style.display = "none";
}
click = 1;
return;
}
}
Though when i onclick=submenuvisible() it works only 1 time. What am I doing wrong?
Your mistake is in your for loops.
Where you have: for (i; i < submenues.length; i++) {
You need to reset the variable i to 0 at the beginning of the for loops.
for (i = 0; i < submenues.length; i++) {
If you don't reset it, then i will remain at the same value it was after the first time you run your function. You could improve your code further by not making i a global variable, but overall, I hope this explains your issue.

How to create a tabbed interface in Javascript

I'm trying to create a tabbed interface in Javascript which will allow a user to click on a button atop each interface in order to make the div under it become active while the other 'tabs'/divs recede to the background. I'm not quite sure I got that out right so attached is a screenshot of what I'm trying to make:
My code attaches one button -- beside the first div-- instead of all three and returns an error that says nodeChildren[j].getAttribute("data-tabname") is not a function although as far as I know, it seems it is.
I'll post my JavaScript code then add a link to fiddle where everything is.
function asTabs(node) {
var button = document.createElement("BUTTON");
var tempArray = [];
var nodeChildren = Array.prototype.slice.call(node.childNodes);
nodeChildren.filter(function(){
for (var i = 0; i < nodeChildren.length; i++) {
if (nodeChildren[i].nodeType === 1) {
tempArray += nodeChildren[i];
return tempArray;
}
}
});
nodeChildren.forEach(function (){
for (var j = 0; j < nodeChildren.length; j++) {
node.insertBefore(button, nodeChildren[j]);
var buttons = document.getElementsByTagName("button");
for (var k = 0; k < buttons.length; k++) {
buttons[k].innerHTML = nodeChildren[j].getAttribute("data-tabname").textContent;
}
}
});
var hide = nodeChildren.slice(1);
for (var l = 0; l < hide.length; l++) {
hide[l].className = "hide";
}
buttons[k].addEventListener("click", function (){
if (nodeChildren[j].className = "") {
nodeChildren[j].className = "hide";
}
else nodeChildren[j].className = "";
});
}
asTabs(document.querySelector("#wrapper"));
Then here's my fiddle containing comments explaining what is being tried to achieve on each line
https://jsfiddle.net/nmeri17/nmswdota/

Does not execute the code after a for within a function

Good! I have a problem and you do not run my code at the end of the loop, the above and what is inside the loop works fine, the problem is that after the loop is still not executing the code. Any idea why it can be?
This is my code:
var arrayp = new Array();
function botonAdelante(tabl, pasos)
{
var padreTabla = document.getElementById(tabl).rows;
var cont = 0;
for(var j = 0; j < padreTabla.length; j++)
{
var hijoTd = document.getElementById(pasos+ "-producto-" +j);
var childArray = hijoTd.children;
for(var i = 0; i < childArray.length; i++)
{
var check = document.getElementById(pasos+ "-CheckBox-" +j);
if(check.type == 'checkbox' && check.checked==true)
{
arrayp[cont] = check.value;
var algo = arrayp[cont];
alert(arrayp[cont]);
alert(arrayp);
cont++;
continue;
};
}
}
alert("It is in this part of the code does not work");
}
Clarification: "continue" found at the end of long and if it will not work either.
The continue is confusing used like this, but I have a feeling your code is probably throwing an error because the cont might exceed the array length. Regardless of whether this fixes it or not I'd at least add a check to ensure that it doesn't throw an exception.
Please check for exceptions being thrown through web dev tools (F12 in Chrome).
for(var i = 0; i < childArray.length; i++)
{
var check = document.getElementById(pasos+ "-CheckBox-" +j);
if(check.type == 'checkbox' && check.checked==true && arrayp.length <= cont)
{
arrayp[cont] = check.value;
var algo = arrayp[cont];
alert(arrayp[cont]);
alert(arrayp);
cont++;
continue;
};
}

Categories