skip to Main Content

I know I have not been the best with coding. But right now I’m having a JavaScript issue. I’m trying to make a random password generator that when you check and uncheck certain boxes it will generate or not generate those specific checked/not-checked boxes. I’ve been trying to get this box to show the random generated password and see if it works but for some reason it will not. I do not know if the issue is because I have option1=> and option2=> but either ways when I delete one of those it still does not show. I’ve done multiple stuff like adding && and getting rid of another code block that is similar to the the options.forEach block. Using the exact code but except for option 1 and 2 it would just be the first block as option1 and the second block as option2. When I do console.log(placeholder) it generates the text "Your secure password" which is the placeholder.
What are my mistakes and how could I get it to generate a password to the console.log
Every time I click the generate button all I get is this(screenshot).

Screenshot of Console.log

enter image description here

options = document.querySelectorAll(".option1 input")
const characters = { //object and letters
  Lowercase: "abcdefghijklmnopqrstuvwxyz",
  Uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  Numbers: "123456789",
  Special: "@#$%&!_&"
}
const generatepassword = () => {
  let password = "";

  options.forEach(option1 => option2 => {
    if (option1.checked && option2.checked) {
      password += characters[option1.id && option2.id];
    }
  })
  console.log(generatepassword);
}

// Get references to the #generate element
var generateBtn = document.querySelector("#generate");

// Write password to the #password input

// Add event listener to generate button
generateBtn.addEventListener("click", generatepassword);
<textarea readonly id="password" placeholder="Your Secure Password" aria-label="Generated Password"></textarea>

<div class="card-footer">
  <button id="generate" class="btn">Generate Password</button>
</div>
</div>
</div>
<section class="options">
  <section class="option1">
    <div id="Uppercase">
      <input type="checkbox" checked> Uppercase
    </div>
    <div id="Lowercase">
      <input type="checkbox" checked> Lowercase
    </div>
  </section>
  <section class="option2">
    <div id="Special">
      <input type="checkbox" checked> Special
    </div>
    <div id="Numbers">
      <input type="checkbox" checked> Numbers
    </div>
  </section>
</section>

2

Answers


  1. You don’t need to check the options in the loop. Use the selected options to produce a string that concatenates all the elements of characters that were selected. Then in the loop pick a random element from that combined string.

    options = document.querySelectorAll(".options div");
    const characters = { //object and letters
      Lowercase: "abcdefghijklmnopqrstuvwxyz",
      Uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      Numbers: "123456789",
      Special: "@#$%&!_&"
    }
    const generatepassword = () => {
      let password = "";
      let chosenCharacters = "";
      let numChars = parseInt(document.querySelector("#count").value);
      options.forEach(div => {
        if (div.querySelector("input").checked) {
          chosenCharacters += characters[div.id];
        }
      });
      for (let i = 0; i < numChars; i++) {
        password += chosenCharacters[Math.floor(Math.random() * chosenCharacters.length)];
      }
      document.querySelector("#password").value = password;
    }
    
    // Get references to the #generate element
    var generateBtn = document.querySelector("#generate");
    
    // Write password to the #password input
    
    // Add event listener to generate button
    generateBtn.addEventListener("click", generatepassword);
    <textarea readonly id="password" placeholder="Your Secure Password" aria-label="Generated Password"></textarea>
    
    <div class="card-footer">
      <button id="generate" class="btn">Generate Password</button>
    </div>
    
    <section>
      How many characters? <input id="count" type="number">
    </section>
    
    <section class="options">
      <section class="option1">
        <div id="Uppercase">
          <input type="checkbox" checked> Uppercase
        </div>
        <div id="Lowercase">
          <input type="checkbox" checked> Lowercase
        </div>
      </section>
      <section class="option2">
        <div id="Special">
          <input type="checkbox" checked> Special
        </div>
        <div id="Numbers">
          <input type="checkbox" checked> Numbers
        </div>
      </section>
    </section>
    Login or Signup to reply.
  2. There were a couple of issues in your code, including the HTML part and JavaScript, which were addressed in the comments of your question. I’ve tried to change them to represent what you were going for as so:

    const options: NodeListOf<HTMLInputElement> = document.querySelectorAll(".option1 input");
    const characters = {
      // object and letters
      Lowercase: "abcdefghijklmnopqrstuvwxyz",
      Uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      Numbers: "123456789",
      Special: "@#$%&!_&",
    };
    
    const generatepassword = () => {
      let password = "";
    
      // Iterate through the option input elements
      for (const option of options) {
        // Check if the current option is checked
        if (option.checked) {
          // If so, add the appropriate characters to the string of characters
          password += characters[option.id];
        }
      }
      console.log(password);
    };
    
    // Get references to the #generate element
    const generateBtn = document.querySelector("#generate");
    
    // Write password to the #password input
    
    // Add event listener to generate button
    generateBtn?.addEventListener("click", generatepassword);
    
    1. Firstly, I typed the options variable as NodeListOf<HTMLInputElement>, because then when we iterate through the children we can check if the element is checked, since not all HTML element have this attribute. The options variable also didn’t have the const keyword, so I added that.
    2. Then, for the loop, I used the for ... of syntax instead of .forEach(), but it’s pretty much the same thing. However, you had the issue of calling forEach with two arrow functions in option1 => option2 => .... You can read up on what they are here, but I believe that’s not what you were going for.
    3. Instead of checking if both options are checked, just go one by one and check if the current option is checked, and if so, add the characters you like. When looping through options we have a loop variable called option, and we don’t actually know which option this stands for in a given moment since it changes with each iteration of the loop. We just test if it’s checked and perform the appropriate operations accordingly. The code with option1.id && option2.id was in error because this would evaluate the two ids as booleans, applying the logical AND operator.
    4. Finally, you were logging the function being called instead of the password variable you created to store the result. This was probably just a typo.

    As an unrelated note, I replaced var with const since it’s deprecated in modern JavaScript.

    But as of ES6, there is an alternative to var: const and let. There is practically zero need to use var anymore, so don’t.

    Additionally, when adding the click event listener, I added optional chaining because if you choose to change the element ID in the HTML without updating the JavaScript, this line of code would throw an exception. Now, it evaluates to a no-op, and prevents the linter from writing up errors.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search