0

I have a simple HTML login form:

const passwordField = document.querySelector("#password");
const eyeIcon = document.querySelector("#eye");

eye.addEventListener("click", function() {
  this.classList.toggle("fa-eye-slash");
  const type = passwordField.getAttribute("type") === "password" ? "text" : "password";
  passwordField.setAttribute("type", type);
})
<script src="https://kit.fontawesome.com/6d0b0e6586.js" crossorigin="anonymous"></script>
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200;400;500;600&display=swap" rel="stylesheet">
<div id="login-flow">
  <section>
    <h1>Welcome back.</h1>
    <form action="#" method="post">
      <label for="email">Email</label>
      <input type="email" id="email" name="email" placeholder="Email" required>
      <label for="password">Password</label>
      <div class="password-container">
        <input type="password" name="password" id="password" placeholder="Password" required>
        <i class="fa-solid fa-eye" id="eye"></i>
      </div>
      <!--pass-toggle-->
      <button type="button" name="btn" id="btn-login">Login</button>
    </form>
    <div class="form-footer">
      <p>Don't have an account? Create one <a href="register.html">here</a>.</p>
    </div>
  </section>
</div><!--login-flow-->

Everything works great except the icon toggle. There are no warnings and the password input field changes between password and text in the console but the icon does not change. Interestingly, if I add the fa-eye-slash class to the <i> in .password-container, and this.classList.toggle to fa-eye, it works perfectly. It’s just that the icons are reversed. Why won’t it work as is?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
  • 1
    Your Font Awesome classes only make sense if there’s _either_ `fa-eye` _or_ `fa-eye-slash` there, not both; otherwise one set of CSS rules will always override the other one. Why not add another `this.classList.toggle("fa-eye");`? – Sebastian Simon Nov 01 '22 at 04:56
  • Thanks Sebastian. Can you explain a bit further? In the tag, I'm only using one FA class, fa-eye, not both. The this.classList.toggle("fa-eye-slash"); is supposed to swap with the fa-eye icon. No? – Thistlefinch Nov 01 '22 at 05:02
  • _“The this.classList.toggle("fa-eye-slash"); is supposed to swap with the fa-eye icon. No?”_ — No, of course not! Why should it? Those are two completely unrelated classes. – Sebastian Simon Nov 01 '22 at 05:06
  • Whey then, if the classes are swapped. . .if the tag has the fa-eye-slash class and the this.classList.toggle("fa-eye"); , do they swap? They are still unrelated. What am I missing? – Thistlefinch Nov 01 '22 at 05:08
  • Not quite sure what you’re asking here, but you basically have classes A and B. If you want to change (only) A to (only) B, you have to toggle A (thus removing A) _and_ toggle B (thus adding B). – Sebastian Simon Nov 01 '22 at 05:15
  • Let me clarify, currently the fa class for the tag is fa-eye. However, if I change it to fa-eye-slash and change the this.classList.toggle to fa-eye, the toggle happens perfectly between the two on click. What's causing the rub is why it won't work as is. – Thistlefinch Nov 01 '22 at 05:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/249211/discussion-between-thistlefinch-and-sebastian-simon). – Thistlefinch Nov 01 '22 at 05:34

2 Answers2

0

you attached the event listener to a non-existing variable. try this

eyeIcon.addEventListener("click", function() {
  this.classList.toggle("fa-eye-slash");
  const type = passwordField.getAttribute("type") === "password" ? "text" : "password";
  passwordField.setAttribute("type", type);
})
Mprizzuto
  • 44
  • 4
  • That’s more of a comment than an answer. It’s correct: `eye` should be `eyeIcon` there. It works because it’s a global property: [Do DOM tree elements with ids become global properties?](/q/3434278/4642212). But this doesn’t answer the question. – Sebastian Simon Nov 01 '22 at 05:07
  • thank you for your suggestion. I will strive to do better in the future – Mprizzuto Nov 01 '22 at 05:08
  • 1
    Thanks Mprizzuto. Adding eye in front of addEventListener doesn't attach it to the correct variable, the const with querySelector #eye? – Thistlefinch Nov 01 '22 at 05:12
  • @Thistlefinch Your variable is called `eyeIcon`, not `eye`. – Sebastian Simon Nov 01 '22 at 05:16
  • Thanks gang. My variable is indeed eyeIcon, missed that one! Still not quite right. – Thistlefinch Nov 01 '22 at 05:25
  • Got it. Sebastian's suggestion of adding a second this.classList.toggle and your input on the incorrect variable were the issues. Thanks much. – Thistlefinch Nov 01 '22 at 05:39
0

here is your solution

eye.addEventListener("click", function() {

  const type = passwordField.getAttribute("type") === "password" ? "text" : "password";
  passwordField.setAttribute("type", type);

   if (passwordField.getAttribute("type") === "password") {
        eyeIcon.classList.remove("fa fa-eye");
        eyeIcon.classList.add("fa fa-eye-slash");
   } else {
        eyeIcon.classList.remove("fa fa-eye-slash");
        eyeIcon.classList.add("fa fa-eye");
   }
})
Rafiul Islam
  • 309
  • 2
  • 8