2

I have three buttons and three JS functions that toggle the display of three different divs. How can I simplify/condense my three JS functions into one function that connects each button to its corresponding content?

Example:

HTML Buttons

<button onclick="myFunction1()">Button 1</button>
<button onclick="myFunction2()">Button 2</button>
<button onclick="myFunction3()">Button 3</button>

HTML Content

<div id="ContentOne">This is Content One.</div>
<div id="ContentTwo">This is Content Two.</div>
<div id="ContentThree">This is Content Three.</div>

JavaScript

function myFunction1() {
    var x = document.getElementById("ContentOne");
    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}

function myFunction2() {
    var x = document.getElementById("ContentTwo");
    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}

function myFunction3() {
    var x = document.getElementById("ContentThree");
    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}

3 Answers 3

5

Add a parameter to the condensed function et violà!

function myFunction(id) {
  var x = document.getElementById(id);
  if (x.style.display === "none") {
    x.style.display = "block";
  } else {
    x.style.display = "none";
  }
}
<button onclick="myFunction('ContentOne')">Button 1</button>
<button onclick="myFunction('ContentTwo')">Button 2</button>
<button onclick="myFunction('ContentThree')">Button 3</button>

<div id="ContentOne">This is Content One.</div>
<div id="ContentTwo">This is Content Two.</div>
<div id="ContentThree">This is Content Three.</div>

Explanation

The only part that differs within the functions is the ID, so decouple the ID. The function does not need to know which element will be affected of the styling adaptions. So keep the function "dump".

Further learning: Anti-Patterns

If you are interested in improving your programming style, I suggest you take a look at some anti-pattern. For example, you demonstrated the antipattern of hard coding. It's not as untypical as you think.

Sign up to request clarification or add additional context in comments.

Comments

2

Inline JS is hard to maintain.
I'd use this code with just a line of CSS to hide elements,
and use JS simply to toggle that .hide class:

const toggleEl = e => document.getElementById(e.target.dataset.tog).classList.toggle("hide");

[...document.querySelectorAll("[data-tog]")].forEach( btn =>
    btn.addEventListener("click", toggleEl)
);
.hide { display: none;}
<button data-tog="ContentOne">Button 1</button>
<button data-tog="ContentTwo">Button 2</button>
<button data-tog="ContentThree">Button 3</button>

<div class="hide" id="ContentOne">This is Content One.</div>
<div class="hide" id="ContentTwo">This is Content Two.</div>
<div class="hide" id="ContentThree">This is Content Three.</div>

https://developer.mozilla.org/en-US/docs/Web/API/Element/classList

Here's a ES5 example if you prefer:

function toggleEl() {
  var id = this.getAttribute("data-tog");
  document.getElementById(id).classList.toggle("hide");
}

var buttons = document.querySelectorAll("[data-tog]");
[].forEach.call(buttons, function( btn ) {
  btn.addEventListener("click", toggleEl.bind(btn))
});
.hide { display: none;}
<button data-tog="ContentOne">Button 1</button>
<button data-tog="ContentTwo">Button 2</button>
<button data-tog="ContentThree">Button 3</button>

<div class="hide" id="ContentOne">This is Content One.</div>
<div class="hide" id="ContentTwo">This is Content Two.</div>
<div class="hide" id="ContentThree">This is Content Three.</div>

3 Comments

Good answer, but he is using ES5 in his question. Your solution is ES6 and does not answer the question, you are proposing a completely different way to solve the question "How to toggle a HTML element with JS?" and not "Multiple JavaScript Buttons Simplified Into One Function". But nevermind ...
@MichaelCzechowski a closer look would reveal you there is actually a toggleEl function that does exactly what OP is asking, and even more. Removing inline JS in favor of data-* attributes, and using a reusable CSS class. (My bad for showing a ES6 example and dataset instead of getAttribute which would be even better).
Your solution is very elegant, no comment on that. I just wanted to say that it could be a bit overwhelming at such an early point of learning JS.
0

You can use a higher order function.

function generateFunction(elementId) {
    return function() {
        var x = document.getElementById(elementId);
        if (x.style.display === "none") {
            x.style.display = "block";
        } else {
            x.style.display = "none";
        }  
    }
}

var myFunction1 = generateFunction("ContentOne");
var myFunction2 = generateFunction("ContentTwo");
var myFunction3 = generateFunction("ContentThree");

2 Comments

Just a note about terminology: Generator function has a different meaning in JS. This is, I suppose, a higher order function. There are plenty of times when this might be the right solution, but I would suggest that the answer from @MichaelCzechowski is simpler in this case.
You're absolutely right - should have cross checked that

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.