Home > database >  Don't Override setTimeout
Don't Override setTimeout

Time:11-28

I am trying to create a notification system that gives custom notifications. Here is my function:

var notificationCount = 0;

document.querySelector("body").innerHTML  = '<div ></div>';

function notification(content){
  notificationCount =1;
  document.querySelector(".notification-holder").innerHTML  = `
  <div  id="notification-${notificationCount}">
      <p>${content}</p>
  </div>
  `;
  var msg = document.querySelector(`#notification-${notificationCount}`);
  msg.style.animation = "notificationAnimate 0.2s forwards"
  msg.addEventListener("animationend", () => {
    msg.style.visibility = "visible";
    msg.style.animation = "";
    setTimeout(() => {
      msg.style.animation="notificationAnimate 0.2s reverse"
      msg.addEventListener("animationend", () => {
        msg.remove()
      })
    }, 1000)
  })
};
:root{
    --black: #151515;
    --white: #EDEDEE;
}

.notification-holder{
    position: absolute;
    bottom: 0px;
    right: 10px;
    padding-bottom: 10px;
    overflow: hidden;
}
.notification{
    width: 250px;
    padding: 10px;
    text-align: center;
    background-color: var(--black);
    color: var(--white);
    font-size: 14px;
    font-family: "Poppins", sans-serif;
    border-radius: 10px;
}
.notification:not(:first-of-type){
    margin-top: 10px;
}

@keyframes notificationAnimate{
    0%{
        opacity: 0;
        max-height: 1px;
        transform: translateY(100px);
        scale: 0;
    }
    100%{
        opacity: 1;
        max-height: fit-content;
        transform: translateY(0px);
        /* visibility: visible; */
        scale: 1;
    }
}
<html>
    <head>
    </head>
    <body>
        <button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
    </body>
</html>

The code works perfectly fine for 1 notification at a time. However, when there are multiple notifications at a time, only the latest one goes through the reverse animation.

Regenerate Problem:

  • Click on the button twice
  • You will see only the latest notification goes back down. Earlier ones just stick there.

Expectation: I want all of them to go back down after 1s of when they were shown.

CodePudding user response:

As noted in my earlier comment, I think the problem comes with you using notificationCount in the ID/selector. That changes over time.

My solution removes the need for that, as well as all the document re-querying you were doing over time. Instead of tracking IDs and querying the DOM repeatedly, I create elements and store references to them, which I later act upon as needed.

My changes are in the JS, the rest of this snippet is from your post:

var notificationContainer,
    notification;

notificationContainer = document.createElement('div');
notificationContainer.className = 'notification-holder';
document.body.appendChild(notificationContainer);

notification = function (content) {
    var msg = document.createElement('div');
    msg.className = 'notification';
    msg.innerHTML = `<p>${content}</p>`;    
    msg.style.animation = 'notificationAnimate 0.2s forwards';
    msg.addEventListener('animationend', function () {
        msg.style.visibility = 'visible';
        msg.style.animation = '';

        setTimeout(function () {
            msg.style.animation='notificationAnimate 0.2s reverse';
            msg.addEventListener('animationend', function () {
                msg.remove();
            });
        }, 1000);
    });

    notificationContainer.appendChild(msg);    
};
:root{
    --black: #151515;
    --white: #EDEDEE;
}

.notification-holder{
    position: absolute;
    bottom: 0px;
    right: 10px;
    padding-bottom: 10px;
    overflow: hidden;
}
.notification{
    width: 250px;
    padding: 10px;
    text-align: center;
    background-color: var(--black);
    color: var(--white);
    font-size: 14px;
    font-family: "Poppins", sans-serif;
    border-radius: 10px;
}
.notification:not(:first-of-type){
    margin-top: 10px;
}

@keyframes notificationAnimate{
    0%{
        opacity: 0;
        max-height: 1px;
        transform: translateY(100px);
        scale: 0;
    }
    100%{
        opacity: 1;
        max-height: fit-content;
        transform: translateY(0px);
        /* visibility: visible; */
        scale: 1;
    }
}
<html>
    <head>
    </head>
    <body>
        <button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
    </body>
</html>

CodePudding user response:

Here you go, may require some fine tuning, but works as expected:

document.querySelector("body").innerHTML  = '<div ></div>';

function notification(content){
  var msg = document.createElement('div');
  msg.innerHTML  = `
  <div >
      <p>${content}</p>
  </div>
  `
  document.querySelector(".notification-holder").appendChild(msg);

  msg.style.animation = "notificationAnimate 0.2s forwards"
  msg.addEventListener("animationend", () => {
    msg.style.visibility = "visible";
    msg.style.animation = "";
    setTimeout(() => {
      msg.style.animation="notificationAnimate 0.2s reverse"
      msg.addEventListener("animationend", () => {
        msg.remove()
      })
    }, 1000)
  })
};
:root{
    --black: #151515;
    --white: #EDEDEE;
}

.notification-holder{
    position: absolute;
    bottom: 0px;
    right: 10px;
    padding-bottom: 10px;
    overflow: hidden;
}
.notification{
    width: 250px;
    padding: 10px;
    text-align: center;
    background-color: var(--black);
    color: var(--white);
    font-size: 14px;
    font-family: "Poppins", sans-serif;
    border-radius: 10px;
}
.notification:not(:first-of-type){
    margin-top: 10px;
}

@keyframes notificationAnimate{
    0%{
        opacity: 0;
        max-height: 1px;
        transform: translateY(100px);
        scale: 0;
    }
    100%{
        opacity: 1;
        max-height: fit-content;
        transform: translateY(0px);
        /* visibility: visible; */
        scale: 1;
    }
}
<html>
    <head>
    </head>
    <body>
        <button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
    </body>
</html>

BTW, nice script :-)

  • Related