0

I need a solution for if-else comparing the classList.contains in JavaScript. when I compare without setInterval the classList not working but I need a solution without setInterval because it's updating everything I need only to work the classList.contains when onclick. please see the code below.

let ctx = document.querySelector('.control');
ctx.onclick = () => {
  box.classList.toggle('rds');
  document.onclick = null; // important idea
  box.classList.remove('ok')

}

setInterval(() => {
  if (box.classList.contains('rds')) {
    document.onclick = () => {
      box.classList.remove('rds');
      box.classList.add('ok')
    }
  } else {
    document.onclick = null; // important idea
  }
}, 1)
.box {
  width: 200px;
  height: 200px;
  background: red;
  transition: 1s;
}

.rds {
  border-radius: 50%;
}

.ok {
  border: 10px dotted blue;
}
<button class="control">Control here</button>

<div class="box" id="box"></div>
leonheess
  • 16,068
  • 14
  • 77
  • 112
NIKHIL CHANDRA ROY
  • 807
  • 11
  • 16

2 Answers2

0

I understood you. But you should also provide behavior of yours animation. I did 2 variants without setInterval please check. And if it is okay for you, mark answer like correct.

jsfiddle 1: https://jsfiddle.net/shuts13/dvp4tea9/21/

jsfiddle 2: https://jsfiddle.net/shuts13/0emocq7j/1/

<button class="control" onclick="update()">Control here</button>

    <div class="box" id="box">

    </div>


    function update() {
  const box = document.getElementById('box');

              box.classList.add('rds');
              box.classList.add('ok');

  setTimeout(()=> {
            if(box.classList.contains('rds')){
                            console.log('ECIS')
                box.classList.remove('rds');
            } 
  }, 1000)
  }
shutsman
  • 2,357
  • 1
  • 12
  • 23
  • not actually which I wanted, I need document and box onclick and without setInterval or setTimeout just remove setInterval from my js code and see, it will not work to document onclick but I need to work document onclick without setInterval or setTimeout , actually the box class not updating after adding new class but I need to update without setInterval – NIKHIL CHANDRA ROY Jan 20 '20 at 12:56
  • @NIKHILCHANDRAROY What behavior do you expect when document detects it has been clicked? All I see is that it does absolutely nothing (`null` to be precise). – zer00ne Jan 20 '20 at 12:59
  • but what do you want to do, I can't understand – shutsman Jan 20 '20 at 13:16
  • click control here button than click document it will add ok class and remove rds class in box class – NIKHIL CHANDRA ROY Jan 20 '20 at 13:38
  • I need this behavior without setInterval – NIKHIL CHANDRA ROY Jan 20 '20 at 13:39
  • okay: `function update() { const box = document.getElementById('box'); box.classList.add('ok'); box.classList.remove('rds'); }` - function adds 'ok' class and remove 'rds' class, as you want, but you dont have rds class in html – shutsman Jan 20 '20 at 15:40
  • one more: ` let ctx = document.querySelector('.control'); ctx.onclick = () => { box.classList.remove('rds'); box.classList.add('ok') }` – shutsman Jan 20 '20 at 15:43
  • WARNING: you should add the Script at the bottom of body when DOM is loaded – shutsman Jan 20 '20 at 16:03
  • when button will click the rds class will add and than document will behave, I had used the script at bottom – NIKHIL CHANDRA ROY Jan 21 '20 at 02:47
0

Problems

The OP 1 (aka Original Poster -- aka @NIKHIL CHANDRA ROY) use (misuse?...abuse?) of setInterval() is just a means to switch the "state" (ex. .ok and .rds) of .box I assume.

Concerning OP's misconceptions about (or perhaps failure to properly explain) the following statement:

document.onclick = null; // important idea

From what I gather is that OP is worried that document will detect the click event and call the event handler, thereby incurring two calls to the event handler in rapid succession. Once by document and the other by .control -- hence the misunderstanding that setInterval() was useful in this particular situation.


Event Handlers / Callbacks 2

OP treats the event handlers as normal anonymous functions (which is why OP is creating two separate functions to change two separate "states" and struggling with when a call happens and when a call shouldn't).

  • Standard Anonymous Function
    Anonymous functions are defined and invoked when parsed. When the browser notices the parenthesis (ex. function()) it will interpret it as: "Run this function NOW").

    const nodeRef = () => {... 
    /* or */  
    var nodeRef = function() {...
    
  • Event Handler
    Event handlers are functions that wait for a registered event to happen before they run. Note the similarities they share:

    //~~~~ Defined (aka Named)
    domNode.onclick = functionName; 
    /* or */ 
    domNode.addEventListener('click', functionName);
    
    function functionName(eventObject) {...
    
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
    //~~~ Anonymous
    domNode.onclick = function(eventObject) {... 
    /* or */ 
    domNode.addEventListener('click', function(eventObject) {...
    
    • When registered event is triggered the event handler is called, thus the only time parenthesis are included is when an event handler is defined. Note a defined event handler does not have parenthesis () because their definitions are hoisted to the top.

    • Also by default event handlers pass the Event Object. Always include it as the first parameter when defining an event handler. By explicitly passing the event object (typically as e, event, evt...) the event handler can access the event object's properties such as event.type, event.currentTarget, and event.target.

    • event.currentTarget is an object (typically a HTMLElement) that is registered to an event (it "listens" for a specific event to happen). It is also referred to as this within the definition of its associated event handler.
    • event.target is the object to which the registered event originated from. For example, if the fifth button out of a hundred identical buttons was clicked, event.target will accurately reference that particular button.

Hopefully what an event handler is and what it does is a little more clearer. Moreover how indispensable Event Object is. The next section explains Event Phases which details the unseen chain of events happening within the DOM tree.


Event Phases

<!DOCTYPE html><!--document-------------------->
<html><!-----------document.documentElement---->
 ...
   <body><!--------document.body--------------->
     <form id="ui"><!--document.forms.ui-----➕--HTMLFormElement Interface
                    ---event.currentTarget---➕--Registered to click event
                    ---this-------------------->
       <button class='ctx'><!--event.target--⏬-->
         CLICKED!
       </button>
       <fieldset class='box ok'><!--event.target.nextElementSibling---❙--->
       </fieldset>
     </form>
    </body>
 </html>

Capture Phase

  • ex. User clicks button.ctx and becomes event.target
    • event.target parent is event.currentTarget (ie form)
    • Event path: document, html, body, form.
    • The path (and current capture phase) ends when the parent of the event origin (aka event.target) has been reached.
    • This phase is rarely used specifically by the developer and is usually disregarded (there some exceptions such as key events)

Target Phase

  • ex. After completing the path from document to the parent element (ie document.forms.ui) of the button the target phase begins
    • Once event.target is determined, the element positioned immediately after it (ie event.target.nextElementSibling) will change "state" (.box.ok OR .box.rd).
    • The event handler stops propagation (ie stops the bubbling phase from continuing) when target phase is completed or .ctx wasn't clicked. This desired behavior is done by ending statement: event.stopPropagation().
    • Event path has only a single reference to event.target.
    • This phase is the most important one because it singles out the clicked button even if there were a thousand buttons.

Bubbling Phase

  • ex. Normally, after the target phase is complete the path is reversed.
    • Since there where no other objectives it's pointless to continue the event chain so event.stopPropagation() prevents the click event from going any further up the DOM tree.
    • Incidentally, this also excludes ancestor elements / objects such as document from the click event.

Consider the programming pattern called Event Delegation.

  • Advantages

    • Multiple targeted elements 3 (aka event.target) -- ex. a <button> user has clicked) can be specified and exclude non-targeted elements 4 (ex. document or body which could interfere and inhibit proper behavior if a click anywhere triggered an event handler).

    • Only register one element to handle one or more targeted elements at once.

    • The targeted elements include ones that are dynamically added in the future as well.

  • Requirements

    • An ancestor element that all te have in common. It can be a top-level object such as document or window but it's better to assign or create an element that is as close to the te as possible. The closer the less likely buggy behavior will occur (such as double calls to event handlers).

    • Register the event to said ancestor element. There are three ways to register an element to an event using plain JavaScript.

      • On-event Property Event
        My personal favorite because it's terse

        document.forms.ui.onclick = ctrl;
        
      • EventListener
        In general the most recommended way -- the only significant difference between them is that the third optional parameter will use the capture phase instead of the default bubbling phase by passing true.

        document.forms.ui.addEventListener('click', ctrl, true);
        
      • On-event Attribute Event
        This way of event handling is as old as dirt and its use is not recommended due to it's many limitations. I have included it just the sake of completeness, DO NOT IMPLEMENT THIS TECHNIQUE.

        <form id='ui' onclick="ctrl(e); return false">
          <button class='ctx' type='button'>THIS IS LAME!</button>
          <fieldset class='box ok'></fieldset>
        </form> 
        
    • When defining the event handler, establish the following:

      • Ensure that the current event.target (remember the event phases are not idle) isn't event.currentTarget. Once that's establish narrow down the possibilities further by using control or ternary statements.

          ...
          if (event.target !== this) {
            if (event.target.classList.contains('ctx')) {...
          ...
        
      • By implementing narrow criterion and using event.stopPropagation(), excluding everything else is simple.

            ...
            } else {
              event.stopPropagation();
            }
          }
          event.stopPropagation();
        }
        

Demo

const ui = document.forms.ui;

ui.onclick = ctrl;

function ctrl(event) {
  const clicked = event.target;

  if (clicked !== this) {
    if (clicked.classList.contains('ctx')) {
      const box = clicked.nextElementSibling;
      box.classList.toggle('ok');
      box.classList.toggle('rd');
    } else {
      event.stopPropagation();
    }
  }
  event.stopPropagation();
}
.ctx {
  font-size: 1.5rem;
  cursor: pointer;
}

.box {
  width: 200px;
  height: 200px;
  background: red;
  border: 0;
  transition: 1s;
}

.rd {
  border-radius: 50%;
}

.ok {
  border: 10px dotted blue;
}
<form id='ui'>
  <button class="ctx" type='button'>Control</button>
  <fieldset class="box ok"></fieldset>
</form>

Footnotes

1 In the SO community (not sure about the SE as a whole), OP is used interchangeably between Original Poster (the member asking the question) or Original Post (the question itself).

2 At times the terms event handler, event listener, and callback may be used to refer to a function called after an event happens. For the purpose of this answer that holds true. For a more definitive explanation refer to this post.

3 The term targeted elements (te)is coined by myself to refer to elements within the DOM that share a common ancestor and can be a potential event.target made possible by well crafted HTML/CSS and JavaScript configured to effectively delegate events.

4 Non-targeted elements (nte) is an ad-hoc term to describe elements that should be excluded from reacting to certain events for various reasons. Commonly nte are the ancestor elements/objects of the event.currentTarget such as document, body, etc. While there are times when high level nodes on the DOM tree serve well as event.currentTarget, it's best to keep event.currentTarget as close to the te as possible.


References

The following references cover other aspects I didn't cover thoroughly in order to avoid info overload (in retrospect I believe I have failed).

HTMLFormElement

const ui = document.forms.ui;

.nextElementSibling

clicked.nextElementSibling;
zer00ne
  • 41,936
  • 6
  • 41
  • 68