0

I want to use the checkedCount variable inside of the generatePassword function in order to not call the function matrixEffect at the end of generatePassword if the value of checkedCount is 0.

I used the argument checkedCountValue to be able to use the variable outside its function. But because I'm calling the generatePassword function at the end of updateSafetyIndicator I'm receiving the error "RangeError: Maximum call stack size exceeded" due to an infinite call of these functions.

const lengthSlider = document.querySelector(".length-wrapper input"),
options = document.querySelectorAll(".container input"),
generateBtn = document.querySelector(".generate-btn"),
copyBtn = document.querySelector(".copy-btn"),
passwordSafetyIndicator = document.querySelector(".safety-indicator"),
passwordInput = document.querySelector(".display-font");

const characters = {
    lowercase: "abcdefghijkilmnopqrstuvwxyz",
    uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    digits: "0123456789",
    specials: "^!$%&|[](){}:;.,*+-#@<>~"
}

// generate password

function generatePassword(checkedCountValue) {
    let staticPassword = "",
    randomPassword = "",
    passwordLength = lengthSlider.value;
    options.forEach(option => {
        if(option.checked) {
            staticPassword += characters[option.id];
        }
    });

    for (let i = 0; i < passwordLength; i++) {
        randomPassword += staticPassword[Math.floor(Math.random() * staticPassword.length)];
    }

    passwordInput.innerText = randomPassword;

    if (checkedCountValue > 0) {
        matrixEffect(randomPassword);
    } 

    updateSafetyIndicator();
}



// matrix effect

const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

let interval = null;

function matrixEffect(password) {  
    let iteration = 0;
    
    clearInterval(interval);
    
    interval = setInterval(() => {
      passwordInput.innerText = passwordInput.innerText
        .split("")
        .map((letter, index) => {
          if(index < iteration) {
            return password[index];
          }
        
          return letters[Math.floor(Math.random() * 26)]
        })
        .join("");
      
      if(iteration >= lengthSlider.value){ 
        clearInterval(interval);
      }
      
      iteration += 1 / 3;
    }, 30);
  };

// safety indicator update

function updateSafetyIndicator() {

    var uppercaseCheck = document.getElementById("uppercase");
    var lowercaseCheck = document.getElementById("lowercase");
    var digitsCheck = document.getElementById("digits");
    var specialsCheck = document.getElementById("specials");
    var passwordLength = lengthSlider.value;
    var checkedCount = 0;
    
    if (uppercaseCheck.checked) {
        checkedCount++;
    }

    if (lowercaseCheck.checked) {
        checkedCount++;
    }

    if (digitsCheck.checked) {
        checkedCount++;
    }

    if (specialsCheck.checked) {
        checkedCount++;
    }

    if (checkedCount == 0) {
        passwordInput.innerText = "Please select first...";
    }

    else if (checkedCount == 1) {
        passwordSafetyIndicator.id = "veryweak";
    }

    else if (checkedCount == 2) {
        passwordSafetyIndicator.id = "weak";
    }

    else if (checkedCount == 3) {
        passwordSafetyIndicator.id = "medium";
    }

    else if (checkedCount == 4) {
        passwordSafetyIndicator.id = "strong";
    }

    if (checkedCount == 4 && passwordLength >= 10) {
        passwordSafetyIndicator.id = "verystrong";
    }

    if (checkedCount == 3 && passwordLength >= 10) {
        passwordSafetyIndicator.id = "strong";
    }

    if (checkedCount == 2 && passwordLength >= 10) {
        passwordSafetyIndicator.id = "medium";
    }

    if (checkedCount == 1 && passwordLength >= 10) {
        passwordSafetyIndicator.id = "weak";
    }

    generatePassword(checkedCount);
}

// slider length update
function updateSlider() {
    document.querySelector(".length-wrapper span").innerText = (lengthSlider.value);
}

updateSlider();


// copy password
function copyPassword(htmlElement) {
    if (!htmlElement) {
        return;
    }

    let password = passwordInput.innerText;

    let inputPassword = document.createElement("input");
    inputPassword.setAttribute("value", password);
    document.body.appendChild(inputPassword);
    inputPassword.select();
    document.execCommand("copy");
    inputPassword.parentNode.removeChild(inputPassword);
    passwordInput.innerText = "COPIED";

    setTimeout (() => {
        passwordInput.innerText = password;
    }, 1300);
}

copyBtn.onclick = function () {
    copyPassword(passwordInput);
}


    

lengthSlider.addEventListener("input", updateSlider);
generateBtn.addEventListener("click", generatePassword);
Barmar
  • 741,623
  • 53
  • 500
  • 612
flexbeatz
  • 17
  • 2
  • 2
    This is somewhat confusing code to follow. Right now there's no "escape clause" from the recursive functions--they unconditionally call each other. If you want that to not happen you need to put a check function in somewhere. – Dave Newton May 22 '23 at 14:41
  • I'm new to the game so don't mind the mess. What should the check function contain? – flexbeatz May 22 '23 at 15:17
  • Whatever you want to use to make the infinite recursion stop. – Dave Newton May 22 '23 at 15:20
  • is there a better way to use a variable outside its function than the one I used in this example that wouldnt cause this infinite recursion – flexbeatz May 22 '23 at 15:22
  • The infinite recursion happens because the two methods **always** call each other--there's no terminating condition that makes one not call the other *(I think)*. You mentioned something about `checkedCount` being the gate, but it's not used to not call the recursive function--only `matrixEffect`, which isn't recursive. – Dave Newton May 22 '23 at 16:39

0 Answers0