3

I'm trying to write a function toggle_active to show the hidden content on a click, and collapse the content again on one more click. Sadly, it does not work. Could you help me modify it?

function toggle_active(this){
  var x = this.nextSibling;
  if (x.style.display === "none") {
    x.style.display = "block";
  } else {
    x.style.display = "none";
  };
}
.daccord_b{
    display:none;
}
<header class="ca_h" onclick="toggle_active(this);">
    <i class="i i-plus ca_hi"></i>
    Title
</header>
<div class="had daccord_b">Hidden content</div>
Akira
  • 2,594
  • 3
  • 20
  • 45

4 Answers4

2

Use method nextElementSibling to return the next element. And it is not necessary to use the if {} operator.

Don't use this for arguments in functions.

The more correct way for your task is method toggle(), which your class uses in css .daccord_b.

function toggle_active(el) {
    var x = el.nextElementSibling;
    x.classList.toggle("daccord_b");
}
.daccord_b {
    display: none;
}
<header class="ca_h" onclick="toggle_active(this);">
    <i class="i i-plus ca_hi"></i>
    Title
</header>
<div class="had daccord_b">Hidden content</div>

Second solution using style.display.

function toggle_active(el) {
    var x = el.nextElementSibling;
    x.style.display = x.style.display === 'block' ? 'none' : 'block';
}
.daccord_b {
    display: none;
}
<header class="ca_h" onclick="toggle_active(this);">
    <i class="i i-plus ca_hi"></i>
    Title
</header>
<div class="had daccord_b">Hidden content</div>
s.kuznetsov
  • 14,870
  • 3
  • 10
  • 25
  • I would like to ask if I can specify the property of `daccord_b` to toggle. For example, `display`. This is for the case `daccord_b` has many properties and we want to change just one of them. – Akira Mar 07 '21 at 20:24
  • @LEAnhDung, Do you mean using `style.display`? – s.kuznetsov Mar 07 '21 at 20:29
  • Yesss. In my project, your function with `classList.toggle` works well, only except for a small issue, i.e, the paragraph is un-indented. On the other hand, my original function (after modified with `nextElementSibling`) keeps the original indentation. But one issue with my function is that: the first click does not change anything. The effect only happens from the second click. Do you have any idea about this problem? – Akira Mar 07 '21 at 20:38
  • @LEAnhDung, I am familiar with this problem. The effect occurs only after the second click, because after the first click your element receives a `display: none` (for example). This is because the style attribute takes precedence over the ccc rules, and an overlap is obtained. – s.kuznetsov Mar 07 '21 at 20:44
  • I thought I already set `display: none;` in CSS? – Akira Mar 07 '21 at 20:45
  • 1
    @LEAnhDung, I made you a second solution using `style.display`. Check, pls. – s.kuznetsov Mar 07 '21 at 20:50
  • Your second one works like a charm. Do you have any idea why `x.classList.toggle("daccord_b")` in your first method changes the indentation of the element? – Akira Mar 07 '21 at 20:59
  • 1
    @LEAnhDung, It's hard for me to guess because I can't see all the code. Oddly enough, the first solution should also work without side effects, because the `div` tag has a default `display: block`. – s.kuznetsov Mar 07 '21 at 21:10
  • Thank you so much @ s.kuznetsov for your dedicated help!. In my html, the default of `daccord_b` is `display: none`. – Akira Mar 07 '21 at 21:22
  • If you have time, I hope that you can have a look at my related question [here](https://stackoverflow.com/questions/66514329/how-to-see-which-js-file-governing-this-click-to-expand-content-on-a-website). This is where all problems arise. – Akira Mar 07 '21 at 21:46
1

You're having some syntax errors in this code. First, I suggest you name the function arguments something other than this because this is a reserved keyword in JavaScript.

Secondly, I recommend consulting with W3School with such simple problems before reaching out, as most of the time, there is a simple solution :)

Here's a link that solves exactly the problem you're describing.

https://www.w3schools.com/howto/howto_js_collapsible.asp

And, here's an example and how you can achieve this:

let content = document.getElementById("content");

function handleClick() {
  if (content.classList.contains("hide")) {
     content.classList.remove("hide");
  } else {
     content.classList.add("hide");
  }
}
.my-content {
  display: block;
}

.my-content.hide {
  display: none;
}
<button onclick="handleClick()">Toggle</button>

<div class="my-content" id="content">Hello, some content</div>

EDIT If you decide to introduce jQuery to your project, you can achieve it even with fever lines of code:

$("[data-collapse]").on('click', function () {
   let target = $(this).data('collapse');
   $(target).toggle();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button data-collapse="#content">Clicker</button>


<div id="content">
My Content
</div>

This makes it abstract and reusable, even allowing you to do things like separate containers:

$("[data-collapse]").on('click', function () {
   let target = $(this).data('collapse');
   $(target).toggle();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<button data-collapse="#target1">Collapse #1</button>
<button data-collapse="#target2">Collapse #2</button>


<div id="target1">
  <h1>I'm Target #1</h1>
</div>

<div id="target2">
  <h1>I'm target #2</h1>
</div>
dev-cyprium
  • 758
  • 2
  • 8
  • 25
1
js:

function toggle_active(id){
      var x = document.getElementById(id);
      if (x.style.display === "none" || x.style.display === "") {
        x.style.display = "block";
      } else {
        x.style.display = "none";
      };
    }

html:

    <header class="ca_h" onclick="toggle_active('HiddenContent');">
   toggle
</header>
<div class="had daccord_b" id='HiddenContent'>Hidden content</div>
1

It is a good practice to use an Event object in you handler function when you can. Please read this post then try fixing your code accordingly: What exactly is the parameter e (event) and why pass it to JavaScript functions?

More about Event.currentTarget here: https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

function toggle_active(evt){
  var x = evt.currentTarget.nextElementSibling;
  x.classList.toggle('daccord_b'); 
}
.daccord_b {
    display: none;
}
<header class="ca_h" onclick="toggle_active(event);">
    <i class="i i-plus ca_hi"></i>
    Title
</header>
<div class="had daccord_b">Hidden content</div>
Jerry Ben
  • 312
  • 4
  • 10