3

I have the following javascript function that runs on keyup inside of an input:

var passwordInput = document.getElementsByName("newPassword")[0].value;

var upperCase= new RegExp('[A-Z]');
var lowerCase= new RegExp('[a-z]');
var numbers = new RegExp('[0-9]');

if ( passwordInput.match(lowerCase) ) {
    $('.strength-check__rule[data-index="1"]').addClass('check-rule--pass');
} else {
    $('.strength-check__rule[data-index="1"]').removeClass('check-rule--pass');
}

if (passwordInput.match(upperCase)) {
    $('.strength-check__rule[data-index="2"]').addClass('check-rule--pass');
} else {
    $('.strength-check__rule[data-index="2"]').removeClass('check-rule--pass');
}

if(passwordInput.match(numbers)) {
    $('.strength-check__rule[data-index="3"]').addClass('check-rule--pass');
} else {
    $('.strength-check__rule[data-index="3"]').removeClass('check-rule--pass');
}

if(passwordInput.length >= 8) {
    $('.strength-check__rule[data-index="4"]').addClass('check-rule--pass');
} else {
    $('.strength-check__rule[data-index="4"]').removeClass('check-rule--pass');
}

The addClasses inside of each conditional simply add a class to an li to show that that condition has been met. I am wondering if anyone has any tips on how I could shorten this or make it more concise, specifically the first three conditions that are very similar.

14
  • Ah, the validation world, the joy! In your shoes I would use a third party lib, yeah it costs extra kb, but it will save you time. In your case, perhaps jqueryvalidation.org might be something you want to look at. Commented May 26, 2016 at 22:25
  • If it weren't dependent upon [data-index="#"], you could condense it all into this ^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.{8}), but it looks like you are tracking individual strengths. Commented May 26, 2016 at 22:31
  • @sln Yep, that's correct...I have a progress bar that is updated based on each conditional. Was just wondering if anyone had any tips on compacting this or making it more concise. Commented May 26, 2016 at 22:38
  • You could condense the code into a for loop and some arrays, but the context can't be changed because of individual tracking. Commented May 26, 2016 at 22:39
  • @sln Yea that's what I was thinking, seems like that would be cleaner. Just not sure exactly how to do it. Want to provide an example for a nice shiny checkmark :) Commented May 26, 2016 at 22:42

4 Answers 4

1

Perhaps this might help save some lines and characters :

var passwordInput = document.getElementsByName("newPassword")[0].value;

var upperCase= new RegExp('[A-Z]');
var lowerCase= new RegExp('[a-z]');
var numbers = new RegExp('[0-9]');

var x = [0,0,0,0];

x[0] = passwordInput.match(lowerCase) ? 1 : 0;
x[1] = passwordInput.match(upperCase) ? 1 : 0;
x[2] = passwordInput.match(numbers) ? 1 : 0;
x[3] = passwordInput.length > 7 ? 1 : 0;

for (var i = 0; i < 4; i++) {
    if (x[i] == 1) {
        $('.strength-check__rule[data-index="' + (i+1) + '"]').addClass('check-rule--pass');
    } else {
        $('.strength-check__rule[data-index="' + (i+1) + '"]').removeClass('check-rule--pass');
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Doubt it can be shortened much more than this:

var passwordInput = $('[name=newPassword]').val();
var tests = {
  1:/[a-z]/.test(passwordInput),
  2:/[A-Z]/.test(passwordInput),
  3:/[0-9]/.test(passwordInput),
  4:passwordInput.length >= 8
};
for(var i=1; i<=4; i++)
  $('.strength-check__rule[data-index=' +i+ ']')
  [ tests[i] ? 'addClass' : 'removeClass' ]('check-rule--pass');

4 Comments

Nice idea using object, I think for (var i in tests) is more appropriate
Relationship-wise, property iteration seems more appropriate, but such would include inherited properties as well without hasOwnProperty. Assuming it isn't extended is just as bad of a practice as extending it in the first place, as it could break later if a script was included later which extended Object to get whatever functionality done which you required. IE has its own issues with it. Call me "behind the times" if you wish, but after 17 years of JavaScript, I leave as much support as possible.
I got your point, but... What's the advantage using object instead array then?
Two advantages: one is because arrays start at index 0, and we're interested in indices 1 through 4. Sure, we could use i+1 but then it harms readability. The second advantage is it makes the association of each of the keys with its test much more clear. If another test needs to be added at some point, the associations aren't lost since by giving each test a specific key, you're making it clear that the keys matter.
0

Based on your script I refactored it to something different. It can be factored even better but the idea is that you have a function that assess the password strength and from that value, you manipulate the strength meter.

<input type="text" name="newPassword" onkeyup="validate();">

<ul class="strength">
    <li class="strength-1">*</li>
    <li class="strength-2">*</li>
    <li class="strength-3">*</li>
    <li class="strength-4">*</li>
</ul>

<script type="text/javascript">

    $('ul.strength').css('list-style-type', 'none').find('li').css('float', 'left').hide();

    function getPasswordStrength(password) {
        var strength = 0;
        if(password.match(/[A-Z]/)) { strength++; }
        if(password.match(/[a-z]/)) { strength++; }
        if(password.match(/[0-9]/)) { strength++; }
        if(password.length > 8) { strength++; }
        return strength;
    }

    function validate() {
        var strength = getPasswordStrength(document.getElementsByName("newPassword")[0].value);

        $('ul.strength').find('li').hide();
        for(var  i = 1; i < strength + 1; i++) {
             $('li.strength-' + i).show();
        }
    }
</script>

Comments

0

I guess you can use a switch .attr() to change the classes, something like:

$("#pass").keyup(function(e) {
var pass = $("#pass").val();
switch (true) {
  case /((?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.{8,})[^ ]*)/.test(pass):
    $("#stenght").attr("class", 'green');
    break;
  case /((?=.*[a-z])(?=.*[A-Z])(?=.*[\d])[^ ]*)/.test(pass): 
    $("#stenght").attr("class",'blue');
    break;
  case /((?=.*[a-z])(?=.*[A-Z])[^ ]*)/.test(pass):
    $("#stenght").attr("class", 'orange');
    break;
  case /((?=.*[a-z])[^ ]*)/.test(pass):
    $("#stenght").attr("class",'red');
    break;
}
  });
.red{color:red;} .orange{color:orange;} .blue{color:blue;} .green{color:green;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="pass" type="text"><br>
<span class="red" id="stenght">PASSWORD STENGHT<span>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.