0

I currently practicing HTML/CSS/DOM(JS) and more focusing on DOM right now. For now, I try to clone the instagram for studying HTML/CSS/DOM. In the DOM part(js), when I try to use event(EventListener), I am curious that "If the other project or Website need so many EventListener,Do I have to declare name.addEventListener("event name", function()) every-time? Can I declare the EventListener at the body or wrapper(div-class) and using event.target, so I don't need to be declared EventListener several times?" I am sorry if I explain so weird and messy. I tried to explain my brain storming thought. I will share my code just in case

This is HTML

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>
        Westagram!
    </title>
    <link rel="stylesheet" href="style/login.css" type="text/css">
    <link rel="stylesheet" href="style/common.css" type="text/css">
    <!-- <link rel="stylesheet" href="js/login.js"> -->
</head>
<body>
    <!-- 아래 모든 div들을 포함하는 제일 상위 Container -->
        <div class="wrapper">
            <div class="logo">
                <p class="westagram">Westagram</p>
            </div>
    <!-- 로그인 섹션 -->
            <div class="login-container">
                <div class="id">
                    <input type="text" id="text" placeholder="Phone number, username, or email" />
                </div>

                <div class="pw">
                    <input type="password" id="password" placeholder="Password">
                </div>

                <div class="bt">
                    <button class="login-btn">Log in
                    </button>
                </div>
            </div>
    <!-- 비밀번호 찾는 섹션 -->
            <div class="click">
                <a class="find-password">Forgot Password</a>
            </div>
        </div>

        <script src="js/login.js"></script>
</html>

This is CSS file

*{
  padding: 0;
  margin: 0;
  text-decoration: none;
  list-style: none;
  box-sizing: border-box;
}

@font-face {
    font-family: instagramFont;
    src:  url("../src/westagram.ttf") format("opentype");
}

.wrapper {
  margin: 250px 250px 0px 250px;
  padding: 30px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  border: solid 1px #D3D3D3;
  width: 500px;
  height: 500px;

}
.wrapper .login-container {
  width: 400px;
  height: 500px;
}
.wrapper .login-container .id{
  margin-top: 70px;
}

#text {
  width: 100%;
  height: 45px;
  border: solid 1px #D3D3D3;
  border-radius: 5px;
  padding-left: 15px;
}

#password {
  width: 100%;
  height: 45px;
  border: solid 1px #D3D3D3;
  border-radius: 5px;
  padding-left: 15px;
}

.wrapper .login-container .bt .login-btn{
  width: 100%;
  height: 45px;
  border: solid 1px #D3D3D3;
  border-radius: 5px;
  /*background-color: #ff000;*/
  background-color: #B2DFFC;
  cursor: pointer;
  /*padding-left: 15px;*/
}
.wrapper .login-container .pw {
  margin-top: 10px;
  margin-bottom: 10px;
}

.wrapper .login-container.bt {

}


.westagram {
  font-size : 60%;
  font-family: instagramFont;
  font-size: 5rem;
}

This is JS code

let id = document.querySelector("#text");
let password = document.querySelector("#password");
let loginButton = document.querySelector(".login-btn")

function active() {
    if(id.value.length > 0 && password.value.length > 0){
        loginButton.style.backgroundColor='#0095F6';
    } else {
        loginButton.style.backgroundColor='#B2DFFC'
    }
}

id.addEventListener("keyup", active)
password.addEventListener("keyup", active)

I really appreciate your help in advance!

JiwanJeon94
  • 385
  • 4
  • 12
  • unclear why you would need to keep declaring it. Is the element being removed and added back? – epascarello Oct 13 '21 at 15:45
  • 3
    Yes, you can, it is called [event delegation](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation). – Teemu Oct 13 '21 at 15:46
  • @epascarello I am sorry I edited it! I add this part "If the other project or Website need so many EventListener" – JiwanJeon94 Oct 13 '21 at 15:47
  • You can add one event listener and have it do multiple things based on the target. But that might not be the best solution. There is no write it once and the entire user session keeps it. When you navigate the page, you would need to rebind the event listeners. – epascarello Oct 13 '21 at 15:48
  • As long as the event receiver (i.e. the thing that you call .addEventListener on) stays alive, you do not add the same `(event name, handling function)` combination to it a second/third/etc time. For DOM elements that means that as long as you don't remove them from the DOM, you only need one listener binding per `(event name, handling function)` pair. (same event, different handlers, or different events, same handler, are a different story). For more clarity, you'll want to find a modern JS tutorial about work with DOM events. – Mike 'Pomax' Kamermans Oct 13 '21 at 15:49
  • @epascarello you mean event.target right? Could you explain in detail what is it the best solution? For me, I thought it would be more clean(?) code rather than declare event everytime – JiwanJeon94 Oct 13 '21 at 15:53
  • Best solution is based on the situation. There is no one solution that fits everything. Yes you would use the target, but the look up can be slow. Add in a bunch of checks to se if it is element A, B,C, D, etc. and you slow up the event listener. – epascarello Oct 13 '21 at 15:56
  • @Mike'Pomax'Kamermans First of all, thank you for sharing your idea for me! But above the my code in js, i have to declare id.addEventListener and password.addEventListener two times for excuting my code properly – JiwanJeon94 Oct 13 '21 at 15:56
  • @epascarello Oh yeap! I totally agree with you! I want to know is there any other way to do it because you also mentioned that the best solution is case by case! Can I ask what does it mean exactly "but the look up can be slow" Does that mean it takes more time to execute? – JiwanJeon94 Oct 13 '21 at 16:00
  • You have to check if target is X, you have to check if it is Y. DOM look up takes time. So if you make a function with a lot of look ups it will be slow. – epascarello Oct 13 '21 at 16:01
  • Right, but that's _not_ "declaring the event listener twice", that's declaring **an** event listener twice, for two different elements. It's like picking up a book, and then picking up another book: you have two books, you're going to need to pick up both. You can, of course, use a normal `[id,password].forEach(...)` if you need to assign the same event `(event name, handling function)` to multiple elements, that's what for loops were invented for: doing the (near-)same thing multiple times =) – Mike 'Pomax' Kamermans Oct 13 '21 at 16:02
  • In your example, you would not even need to check `event.target` when doing event delegation. Just do `document.querySelector(".login-container").addEventListener("input", active);` – trincot Oct 13 '21 at 16:07

2 Answers2

0

Can you add one event listener? Yes. It is event delegation. You use the target and you do checks to see if it is the element. Multiple ways to check if the element is the same. You can use is(), you can check a class/id/attribute or you can see if the elements match a reference

document.body.addEventListener("input", function (evt) {
   const target = evt.target;
   if (target.closest('#inp1, #inp2')) {
      console.log(target.value);
   }
});
<input type="text" id="inp1" class="loginInput" />
<input type="text" id="inp2" class="loginInput" />

document.body.addEventListener("input", function (evt) {
   const target = evt.target;
   if (target.classList.contains("loginInput")) {
      console.log(target.value);
   }
});
<input type="text" id="inp1" class="loginInput" />
<input type="text" id="inp2" class="loginInput" />

var inp1 = document.querySelector("#inp1");
var inp2 = document.querySelector("#inp2");

document.body.addEventListener("input", function(evt) {
  const target = evt.target;
  if (target === inp1 || target === inp2) {
    console.log(target.value);
  }
});
<input type="text" id="inp1" class="loginInput" />
<input type="text" id="inp2" class="loginInput" />

In the inputs are in the same container, you might not even care what input it is. Just bind the event listener to the parent. Any action inside of it will be picked up.

document.querySelector('#login').addEventListener("input", function(evt) {
  const target = evt.target;
  console.log(target.value);
});
<form id="login">
  <input type="text" id="inp1" class="loginInput" />
  <input type="text" id="inp2" class="loginInput" />
</form>
epascarello
  • 204,599
  • 20
  • 195
  • 236
-1

You can write a function to prevent repeating exactly the same event listeners:

function eventHandler(event, func, target ){
    return target.addEventListener(event, func);
}

eventHandler("keyup", active, id);
OrcunSelbasan
  • 144
  • 1
  • 11