Skip to content
Advertisement

Displaying a concat array in an HTML element

I have multiple arrays that have been combined depending on user response. The only problem I have at this point is getting this final array to show up in the text field for the end user to see. Thanks for all the potential help!

var generateBtn = document.querySelector("#generate");

//write password function 
function writePassword(){
  var password = generatePassword();
  var passwordText = document.querySelector("#password");
  passwordText.value = password;
}

// Add event listener to generate button
generateBtn.addEventListener("click", writePassword)



//defining global var
var lowercase = 'abcdefghijklmnopqrstuvwxyz'
var uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
var number = '1234567890'
var special = '!@#$%^&*()'
//generate password function gets called in writePassword function, and it should return the final password
function generatePassword(){

//blank array that will be the final password that is appended and shown to user
var chosenPassword = ''

//password length function
var passwordLength = prompt('How long would you like your password to be? (must be between 8 and 128 characters)')
if (passwordLength < 8 || passwordLength > 128) {
    alert('Must be between 8 and 128 characters!')
    return generatePassword();
}
//if boolean statements
var hasUpper = confirm('Would you like your passwords to have uppercase characters?')
  if (hasUpper === true) {
    chosenPassword = uppercase.concat(chosenPassword);
  }
var hasLower = confirm('Would you like your passwords to have lowercase characters?')
  if (hasLower === true) {
    chosenPassword = lowercase.concat(chosenPassword);
  }
var hasNumber = confirm('Would you like your passwords to have numbers?')
  if (hasNumber === true) {
    chosenPassword = number.concat(chosenPassword);
  }
var hasSpecial = confirm('Would you like your passwords to have special characters?')
  if (hasSpecial === true) {
    chosenPassword = special.concat(chosenPassword);
  }
//failsafe for no user info given
if (!passwordLength || !hasLower && !hasUpper && !hasNumber && !hasSpecial) {
  alert('Must provide some info to be contained in your password!')
}

//selecting rand function for chosenPass string
for (var i = 0; i < passwordLength; i++) {
  password += chosenPassword.charAt(Math.floor(Math.random() * chosenPassword)) 
}
return password;

}

I have narrowed the problem to either the write function or the generate function. The booleans and math.random functionality are working as expected and have confirmed this in the console.

EDIT: Adding HTML for those who have asked. As well as deleting the redundant function that was the same as the write password function.

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, 
      initial-scale=1.0" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <title>Password Generator</title>
      <link rel="stylesheet" href="style.css" />
   </head>
   <body>
      <div class="wrapper">
      <header>
         <h1>Password Generator</h1>
      </header>
      <div class="card">
         <div class="card-header">
            <h2>Generate a Password</h2>
         </div>
      <div class="card-body">
         <textarea
          readonly
          id="password"
          placeholder="Your Secure Password"
          aria-label="Generated Password"
         ></textarea>
      </div>
      <div class="card-footer">
         <button id="generate" class="btn">Generate 
         Password</button>
      </div>
     </div>
    </div>
     <script src="script.js"></script>
   </body>
  </html>

Advertisement

Answer

Several issues:

  • enterpassword is a function that is never used (and has a spelling issue and missing parentheses). It looks to have the same purpose as writePassword, so it can be removed.
  • passwordLength is going to be a string, better convert it immediately to a number data type, or else code will continue with some invalid input like “one”
  • The expression for getting a random character is wrong. It should have chosenPassword.length instead of chosenPassword.
  • The algorithm does not ensure that at least one character from each selected character group is taken. It only makes sure no other character is taken.

Some other remarks:

  • Using prompt is not very user-friendly, as user is forced to follow that input path and cannot go back to change a previous answer. Use input elements instead (number and checkbox types), so that when user clicks the button, all input is already there.

  • Avoid code repetition, and deal with each character group using the same code in a loop.

To ensure at least one character is taken from each selected character group, you could take a random character from each group, then append random characters from any group (like you did, or by shuffling & slicing), and then shuffle to get those first characters at random places too.

Here is your code adapted to work like that:

var generateBtn = document.querySelector("#generate");
generateBtn.addEventListener("click", writePassword)

function writePassword(){
    var password = generatePassword();
    var passwordText = document.querySelector("#password");
    passwordText.value = password;
}

function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

function randomFrom(arrayLike) {
    return arrayLike[Math.floor(Math.random() * arrayLike.length)];
}

// Avoid code repetition: deal with groups in an array and loops
var groups = [
    'abcdefghijklmnopqrstuvwxyz',
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    '1234567890',
    '!@#$%^&*()',
];

function generatePassword() {
    var passwordLength = +document.querySelector("#length").value;
    if (Number.isNaN(passwordLength) || passwordLength < 8 || passwordLength > 128) {
        alert('Password length must be between 8 and 128 characters!')
        return;
    }
    var checkboxes = document.querySelectorAll("[type=checkbox]");
    var hasGroup = groups.map((group, i) => checkboxes[i].checked);
    if (!hasGroup.includes(true)) {
        alert('Must select some character groups to be contained in your password!')
    }

    // Collect all allowed characters
    var password = groups.filter((group, i) => hasGroup[i]).flatMap(s => [...s]);
    // Collect one character from each required group
    var needed = groups.map((group, i) => hasGroup[i] ? randomFrom(group) : "").filter(Boolean);
    shuffle(password);
    // Get the right number of characters, appending the required ones
    password.splice(passwordLength - needed.length, Infinity, ...needed);
    // Don't leave the needed characters at the end
    shuffle(password);
    return password.join("");
}
Password length: <input id="length" type="number" value="8" min="8" max="128" style="width:3em"><br>
<input id="lowercase" type="checkbox" checked> Needs lowercase letter(s)<br>
<input id="uppercase" type="checkbox"> Needs uppercase letter(s)<br>
<input id="uppercase" type="checkbox"> Needs digit(s)<br>
<input id="uppercase" type="checkbox"> Needs special character(s)<br>
<button id="generate">Generate =></button>
<input id="password">

With prompt and confirm

Not ideal, but if you really have to do this with prompt and confirm, then you can still reuse the logic of the above code, but change the input method:

function getInputs() {
    while (true) {
        var passwordLength = prompt('How long would you like your password to be? (must be between 8 and 128 characters)');
        if (passwordLength >= 8 && passwordLength <= 128) break; // OK
        alert('Must be between 8 and 128 characters!');
    }
    while (true) {
        var hasGroup = ["uppercase", "lowercase", "numeric", "special"].map(group => {
            return confirm('Would you like your passwords to have ' + group + ' characters?')
        });
        if (hasGroup.includes(true)) break; // OK;
        alert('Must provide some info to be contained in your password!');
    }
    return [passwordLength, ...hasGroup];
}

var generateBtn = document.querySelector("#generate");
generateBtn.addEventListener("click", writePassword)

function writePassword(){
    var password = generatePassword();
    var passwordText = document.querySelector("#password");
    passwordText.value = password;
}

function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

function randomFrom(arrayLike) {
    return arrayLike[Math.floor(Math.random() * arrayLike.length)];
}

// Avoid code repetition: deal with groups in an array and loops
var groups = [
    'abcdefghijklmnopqrstuvwxyz',
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    '1234567890',
    '!@#$%^&*()',
];

function generatePassword() {
    // Prompt user for inputs (yuk!)
    var [passwordLength, ...hasGroup] = getInputs();
    // Collect all allowed characters
    var password = groups.filter((group, i) => hasGroup[i]).flatMap(s => [...s]);
    // Collect one character from each required group
    var needed = groups.map((group, i) => hasGroup[i] ? randomFrom(group) : "").filter(Boolean);
    shuffle(password);
    // Get the right number of characters, appending the required ones
    password.splice(passwordLength - needed.length, Infinity, ...needed);
    // Don't leave the needed characters at the end
    shuffle(password);
    return password.join("");
}
<button id="generate">Generate =></button>
<input id="password">
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement