简体   繁体   中英

How to change password visibility when clicking outside of a password field

I am trying to create a password field that allows the user to click the eye icon to view or hide their password. However, on top of this, I would like to hide the password automatically when the user clicks outside the field. this requires a click and blur event. The problem is the blur event runs before the click event and runs when I click the eye icon. This causes the field to be toggled twice because it runs in the blur event block, then in the click event block.

I basically need it to allow me to toggle by clicking the eye icon and also set the field back to password type when exiting the field. I tried using onmousedown but it behaves really weird, it only works when I am stepping through on devtools.

 function togglePassword(element) { $(element).toggleClass("fa-eye fa-eye-slash"); $(element).siblings("input").each(function() { if ($(element).hasClass('fa-eye-slash')) { $(this).attr('type', 'text'); $(this).focus(); } else if ($(element).hasClass('fa-eye')) { $(this).attr('type', 'password'); } }); } function toggleWhenExiting(element) { console.log("focus toggle"); $(element).siblings("span").each(function() { if ($(this).hasClass('fa-eye-slash')) { $(element).attr('type', 'password'); $(this).toggleClass("fa-eye fa-eye-slash"); } }); }
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <input type="password" id="passwordFirst" class="form-control" onblur="toggleWhenExiting(this)"> <span class="fas fa-eye" id="togglePassword" onclick="togglePassword(this)"></span> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

We can simplify and clarify things by using constants for the two elements and using jQuery's one() method to create an event handler that only fires once. Notice that I've removed all event handlers from the markup to modernize with separation of concerns.

We can also check the relatedTarget on blur and only take action if it's not the toggle button. Note that I've added tabindex="0" to that element to make it focusable. Without that it isn't reported as the blur target.

 $('#togglePassword').click(function() { const eyeIcon = $(this); const pwdInput = $('#passwordFirst'); pwdInput.off('blur'); if (eyeIcon.hasClass('fa-eye')) { eyeIcon.removeClass('fa-eye').addClass('fa-eye-slash'); pwdInput.attr('type', 'text').focus(); pwdInput.one('blur', function(e) { if ($(e.relatedTarget).attr('id').== 'togglePassword') { pwdInput,attr('type'; 'password'). eyeIcon.removeClass("fa-eye-slash");addClass('fa-eye'); } }). } else { eyeIcon.removeClass('fa-eye-slash');addClass('fa-eye'). pwdInput,attr('type'; 'password'); } });
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <input type="password" id="passwordFirst" class="form-control"> <span class="fas fa-eye" id="togglePassword" tabindex="0"></span> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

By monitoring time, repeated action could be detected. In the following code, the toggleWhenExiting function also calls the togglePassword function for toggling the view. The main key is preventing togglePassword function from running twice in less than 200ms. var timems = (new Date()).getTime() is used to get the time in ms and if(timems - $(element).attr('lastrun') < 200) return; calculate time distance from last run.

 function togglePassword(element) { console.log("span clicked"); var timems = (new Date()).getTime() if(timems - $(element).attr('lastrun') < 200) return; $(element).attr('lastrun', timems); $(element).toggleClass("fa-eye fa-eye-slash"); $(element).siblings("input").each(function() { if ($(element).hasClass('fa-eye-slash')) { $(this).attr('type', 'text'); $(this).focus(); } else if ($(element).hasClass('fa-eye')) { $(this).attr('type', 'password'); } }); } function toggleWhenExiting(element) { console.log("focus toggle"); $(element).siblings("span").each(function() { if ($(this).hasClass('fa-eye-slash')) $(this).click(); }); } </script>
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <input type="password" id="passwordFirst" class="form-control" onblur="toggleWhenExiting(this)"> <span class="fas fa-eye" id="togglePassword" onclick="togglePassword(this)"></span> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

While I think I prefer isherwoods answer I'll leave this here for something else to think about

Here we use css to toggle the icon based on the type attribute of the preceding input element. A little use of the element inspector revealed the unicode for the content of the icon.

Next we use a div to combine the elements adding tabindex=0 again to make it "blurable". When this combined element loses focus, then set the input back to password

 /*Toggle password field on eye click*/ $(".togglePassword >.fas").click(function() { //Get currnet status var currentType = $(this).prev("input").attr("type"); //toggle the password field $(this).prev("input").attr("type", currentType == "password"? "text": "password"); }) /*Set back to password when our combined element loses focus*/ $(".togglePassword").blur(function() { $(this).find("input").attr("type", "password"); })
 /*Use CSS to toggle the eye icon based on type attribute of previous element*/.togglePassword>[type=password]+.fas::before { /*eye icon*/ content: "\f06e"; }.togglePassword>[type=text]+.fas::before { /*slashed eye icon*/ content: "\f070"; }
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <div class="togglePassword" tabindex="0"> <input type="password" id="passwordFirst" class="form-control"> <span class="fas"></span> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

You should to add event listener click on your window and check if target is your eye by id or other html attribute.

You could just remove any function from the eye icon altogether if it is in opened state. Let your blur callback take care of all of it!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM