Reputation: 652
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>
Upvotes: 2
Views: 2276
Reputation: 19772
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 addingtabindex=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>
Upvotes: 0
Reputation: 1525
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>
Upvotes: 2
Reputation: 61083
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>
Upvotes: 6
Reputation: 968
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!
Upvotes: -2