Patrick McDermott
Patrick McDermott

Reputation: 1220

Dynamically adding and removing CSS

I have a password strength bar which which uses li items which are styled with different colours to indicate to the user how strong their password is, like so:

<input type="password" name="password" id="password" placeholder="Password">

<ul id="passwordStrength">
    <li class="point-reg"></li>
    <li class="point-reg"></li>
    <li class="point-reg"></li>
    <li class="point-reg"></li>
</ul>

When a regEx criteria has been met through a set of if statements, the counter is incremented and a switch statement then adds the necessary CSS background property to each li item depending on the counter value.

var password_li = $('#passwordStrength').find('li');

var counter = 0;

if(pw.match(/[A-Z]/) && pw.match(/[a-z]/)) {
    counter++;
}

//further regex if statements

switch(counter) { //patrick
    case 0:
    break;
    case 1:
        $(password_li[0]).css('background', '#e30613'); //first li

    break;
    case 2:
        $(password_li[0]).css('background', '#e30613'); //first li
        $(password_li[1]).css('background', '#f9b233'); //second li         

    break;
    case 3:
        $(password_li[0]).css('background', '#e30613'); //first li
        $(password_li[1]).css('background', '#f9b233'); //second li                 
        $(password_li[2]).css('background', '#53ab58'); //third li                  

    break;
    case 4:
        $(password_li[0]).css('background', '#e30613'); //first li
        $(password_li[1]).css('background', '#f9b233'); //second li             
        $(password_li[2]).css('background', '#53ab58'); //third li                                  
        $(password_li[3]).css('background', '#418746'); //fourth li 
    break;
}

This doesn't seem the most efficient way of styling the li items. Also, if the user then deletes the value they have entered, the li items remain the colour they have been assigned, rather than reverting back to their default colour of grey, which makes sense as there isn't a function in place to remove the styling. I can add grey to the li items depending on what case has been met in the switch statement like so:

case 1:
    $(password_li[0]).css('background', '#e30613');
    $(password_li[1]).css('background', '#dcdcdc');                 
    $(password_li[2]).css('background', '#dcdcdc');                 
    $(password_li[3]).css('background', '#dcdcdc');                             
break;

But again, this does not seem the most efficient apporach.

Question

How do I approach this functionality so the styling for the li elements can be dynamically added and removed?

Here is a JSFiddle

Upvotes: 2

Views: 643

Answers (3)

Satpal
Satpal

Reputation: 133453

I would recommend adding/removing CSS classes rather than manipulating CSS rules.

You can persist which class to be add along with <li> element using custom data-* prefixed attribute.

Then you can target the elements on which classes needs to added using .filter() method and :lt() selector.

Fiddle

$(document).ready(function() {
  var password_li = $('#passwordStrength').find('li');
  $('#password').bind('keyup', function() {
    var counter = 0;
    var pw = $(this).val();

    if (pw.length >= 8) {
      counter++;
    }
    if (pw.match(/\d/)) { //match digit
      counter++;
    }
    if (pw.match(/[A-Z]/) && pw.match(/[a-z]/)) { //match digit
      counter++;
    }
    if (pw.match(/[$@$!%*#?&]/)) { //match digit
      counter++;
    }
    //Get all classes to remove
    var clssesToRemove = password_li.map(function() {
      return $(this).data('matched-class');
    }).get().join(' ');

    //Remove all class
    password_li.removeClass(clssesToRemove);

    //Filter and add class
    password_li.filter(':lt(' + counter + ')').each(function() {
      $(this).addClass($(this).data('matched-class'));
    });

  })
})
ul#strength {
  display: inline;
  list-style: none;
  padding: 0;
  vertical-align: 2px;
}

.point-reg {
  background: #DDD;
  border-radius: 2px;
  display: inline-block;
  height: 10px;
  margin-right: 2px;
  width: 30px;
}

.first {
  background-color: #e30613;
}

.second {
  background-color: #f9b233;
}

.third {
  background-color: #53ab58;
}

.fourth {
  background-color: #418746;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<div class="row">
  <div class="col-xl-8 offset-xl-2">
    <div class="form-group row">
      <div class="col-md-12">
        <input type="password" name="password" class="form-control pill-radius font-body" id="password" placeholder="Password">
      </div>
      <div class="form-group row">
        <div class="col-md-12">
          <ul id="passwordStrength">
            <li class="point-reg" data-matched-class="first"></li>
            <li class="point-reg" data-matched-class="second"></li>
            <li class="point-reg" data-matched-class="third"></li>
            <li class="point-reg" data-matched-class="fourth"></li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</div>

Upvotes: 1

First, there's actually a method to remove the styling. Simply set it to nothing:

$(password_li[0]).css({
    background: ""
});
// I guess that can be done inline too
$(password_li[0]).css("background", "");

But if you prefer to do it with less iterations, you can do it with CSS classes. Just set your parent element a class and the class will have a nth-child selector that will set the color of each child, individually, depending on their position.

<style>
    .list1 > li:nth-child(1) {
        background: #e30613;
    }
    .list2 > li:nth-child(2) {
        background: #f9b233;
    }
    .list3 > li:nth-child(3) {
        background: #53ab58;
    }
    .list4 > li:nth-child(4) {
        background: #418746;
    }
    .list5 > li:nth-child(5) {
        background: red;
    }
    .list6 > li:nth-child(6) {
        background: blue;
    }
</style>
<input type="password" name="password" id="password" placeholder="Password">

<ul id="passwordStrength">
    <li class="point-reg"></li>
    <li class="point-reg"></li>
    <li class="point-reg"></li>
    <li class="point-reg"></li>
</ul>

Then you can add the classes to the parent depending on the counter, like this

counter && $("#passwordStrength").addClass("list" + counter);

And remove them when not needed

while(counter) {
    $("#passwordStrength").removeClass("list" + counter--);
}

This way you can have the styles in other file, as recommended, instead of using inline styling, which is discouraged.

Fiddle: https://jsfiddle.net/b6jfgyvy/

Upvotes: 2

meewog
meewog

Reputation: 1740

Maybe you can do something like this

colours = [
    '#e30613',
    '#f9b233',
    '#53ab58',
    '#53ab58'
];

for (i = 0; i < counter; i++) {
    $("password_li[" + i + "]").css('background', colours[i]);
}

You can reset all colours by:

$("password_li").css('background', '#dcdcdc');

Upvotes: 0

Related Questions