Script for showing/hiding on click - how can I write this code cleaner? I have this simple code, but it's messy - how do I do it cleaner?
It works like this: If you click on the menu-btn1 the div shows up, and hide others, but if you click on menu-btn1 again it will hide as well.
let coll = document.getElementsByClassName('collection');
let dis = document.getElementsByClassName('display');
let drop = document.getElementsByClassName('drop');

document.getElementById(&quot;menu-btn1&quot;).addEventListener(&quot;click&quot;, function() {
  if(coll[0].style.display == 'none') {
    coll[0].style.display = 'block';
    dis[0].style.display = 'none';
    drop[0].style.display = 'none';
  } else {
    coll[0].style.display = 'none';
  }
});

&lt;div class=&quot;menu&quot;&gt;
    &lt;span id=&quot;text&quot;&gt;&lt;span id=&quot;menu-btn1&quot;&gt;collection&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class=&quot;collection&quot; style=&quot;display:none;&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;display&quot; style=&quot;display:none;&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;drop style=&quot;display:none;&quot;&gt;&lt;/div&gt;

There is nothing important in css really, only the grid positioning.
First I think that using document.querySelector seems much user friendly than using document.getElementsByClassName. Instead of let coll = document.getElementsByClassName('collection'); coll[0].xxx, we can just use document.querySeletor('collection').xxx.
So code can refactor a bit to
    let coll = document.querySelector('.collection');
    let dis = document.querySelector('.display');
    let drop = document.querySelector('.drop');

    document.getElementById(&quot;menu-btn1&quot;).addEventListener(&quot;click&quot;, function() {
        if(coll.style.display == 'none') {
            coll.style.display = 'block';
            dis.style.display = 'none';
            drop.style.display = 'none';
        } else {
            coll.style.display = 'none';
        }
    });

Next, I will place the DOM retrieval code into the event handler, to prevent unnecessary namespace pollution. Though maybe in your working code, you may use the coll for other handling, then it is okay to place there. In addition, I don't think one will change the variable of a DOM to other value, so I would use a constant instead.
    document.getElementById(&quot;menu-btn1&quot;).addEventListener(&quot;click&quot;, function() {
        const coll = document.querySelector('.collection');
        const dis = document.querySelector('.display');
        const drop = document.querySelector('.drop');
        if(coll.style.display == 'none') {
            coll.style.display = 'block';
            dis.style.display = 'none';
            drop.style.display = 'none';
        } else {
            coll.style.display = 'none';
        }
    });


However these changes does not resolve the fact that display: none is actually scattered in both HTML and Javascript. I think a better idea is just to place the code in one place. That is remove the styling in HTML.

To do so, I think there are possibly 2 approaches, one is the use of RxJS, another way is to use of data driven approach, e.g. React, Angular, Vue, ...
Data Driven Approach: Use of VueJS
Let's first have a look at How we can implement it in Data Driven Approach.
I will use Vue for demonstration, as it is the simplest to setup among the three.


new Vue({
            el: "#app",
            template: `
            &lt;div class="ui"&gt;
                &lt;div class="menu"&gt;
                    &lt;span id="text"&gt;&lt;span @click="show = !show"&gt;collection&lt;/span&gt;&lt;/span&gt;
                &lt;/div&gt;

                &lt;div class="collection" :style="styles"&gt;
                    Collection Inside
                &lt;/div&gt;
            &lt;/div&gt;
            `,
            data: function() {
                return {
                    show: false
                }
            },
            computed: {
                styles: function() {
                    return {
                        "display": this.show ? "block": "none"
                    };
                },
            },
        })
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"&gt;&lt;/script&gt;
&lt;div id="app"&gt;
  &lt;/div&gt;



As you can see, the HTML code is now placed in Javascript as a template, and we make use of :style and @click in the template, instead of normal HTML. These are Vue specific
syntax and is used in Vue for easy interaction between the Vue component Javascript and the template.
Event Driven Approach: RxJS
Another approach would be RxJS, that just work without a framework, so makes it more easy to adopt in a legacy web application.


rxjs.merge(
    rxjs.of(1), // so that it immediately triggers
    rxjs.fromEvent(document.querySelector("#menu-btn1"), 'click'),
)
    .pipe(
        rxjs.operators.scan((accum, value, index) =&gt; {
            return index % 2 == 1;
        }, false)
    ).subscribe(show =&gt; {
        const coll = document.querySelector(".collection");
        const value = show ? "block" : "none";
        coll.style.display = value;
    }

    )
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.3/rxjs.umd.min.js"&gt;&lt;/script&gt;
&lt;div class="menu"&gt;
    &lt;span id="text"&gt;&lt;span id="menu-btn1"&gt;collection&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="collection"&gt;
    Collection Inside
&lt;/div&gt;



Here is all the solution I think of, and it is left to you to decide which way is the cleanest code. To me, I just like the way RxJS is constructed, and do not need to maintain an extra data for storage.