2

Today I was pseudo-coding a we and then I tried to make a hide/show content function for mobile browser.

The problem is (not my hardcoded thing), it's the delay of the button to hide or show content and I think it's because it's not previously initialized.

HTML:

<article id="horarios">
 <h2>Horarios <a onclick="showContent(parentNode.parentNode.id, this.id)" class="showContentBtn" id="showContentBtnHr">&#xe808;</a></h2>
  <span id="hide-horarios">

About my hardcode thing I just make that "parent, parent id" (Horarios) concat with "hide-", I don't know a better solution now but in some way it's ok.

Now here's the problem:

JS:

    function showContent(value, value2){
      var value="hide-"+value;
      var content = document.getElementById(value).style.display;
      if(content == "none"){
        document.getElementById(value).style.display = "block";
        document.getElementById(value2).innerHTML = "&#xe809;";
      }
      else{
        document.getElementById(value).style.display = "none";
        document.getElementById(value2).innerHTML = "&#xe808;";
      }
    }

CSS

#hide-programas, #hide-horarios, #hide-aboutus{
  display: none;
}

When I test it, I have to click one time and it do nothing then it works. I think this is because "content" not have any value on it to compare so there's nothing to do the first time and then it have a value.

It's possible to fix it? I know it will hurt your eyes but this weird sh*t works in some way.

8
  • It's because .style.display returns an empty string the first time, as it's not set. Commented Sep 9, 2016 at 4:46
  • @adeneo Sorry, I forgot to add the CSS code. In the CSS code the "hide-horarios" is set display:"none";. Commented Sep 9, 2016 at 4:48
  • That doesn't help at all, it still returns an empty string unless the style is set inline, just try it. Commented Sep 9, 2016 at 4:50
  • You can't use parentNode.parentNode.id unless you've initialised a global parentNode variable, perhaps you mean this.parentNode.parentNode.id. And why would you do that just to get the ID so you can call getElementById, why not just pass the elements? showContent(this.parentNode.parentNode, this) then just use el0 and el1 in the function, removing all those redundant document.getElementById calls. Commented Sep 9, 2016 at 4:54
  • @adeneo It's crazy! I tried with visibility and it "worked" the space remains the text is gone but when I tried to add to display it stopped working. Then I remember about you said nothing on it and just put a "" as condition, so it worked. Thanks! You prevent me spend the night doing this. Commented Sep 9, 2016 at 4:58

2 Answers 2

1

This is best fixed by hiding and showing using a class rather than direct access to DOM properties. Below is just a brief example, e.g.

function toggleClass(id, className) {
  var el = document.getElementById(id);
  if (el && el.classList && el.classList.toggle) {
    el.classList.toggle(className);
  }
}
<head><style type="text/css">
  .hidden {
    display: none;
  }
</style></head>

<body>
  <div class="hidden" id="d0">I'm a div</div>
  <button onclick="toggleClass('d0','hidden')">Toggle div</button>
</body>

It's not too hard to support browsers that don't support the classList object if you need to go back that far (IE 9 and lower).

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

1 Comment

Nah, forgot about IE. Because the web uses HTML5 audio tag and flexbox and I already use Modernizr for that. Thanks for the reply +1.
0

Why doesn't it work?

Your Javascript gets the element's style directly from the its HTML, so it is trying to read the contents of display style from the HTML hide-horarios element. However, at the start, this isn't set - you've defined the style in your CSS, as far as Javascript sees it, the style attribute does not exist, and thus neither does the display style.

Instead, it is set to null.

So, what happens when we click the button the first time? Well, there is no style element yet (it doesn't exist in the HTML markup), so the content variable is set to null (as there is no value). So, your if statement is then running a condition which becomes if (null == "none") - of course, we know that that will evaluate to true, so it runs the else part of your code, which sets the display style to none. This now means that the style attribute has been created, and that the display style inside of that has been set (by Javascript).

Next time the function runs, style.display will not be null, but instead none. So, your code will run as intended.

What can we do?

There are a few solutions to your problem. Here I will discuss four:

  1. Add the style attribute to your <span id="hide-horarios"> element like so:

     <span id="hide-horarios" style="display:none">
    

    This is the most obvious solution, and works because the style attribute is now defined so it can be read with Javascript.

  2. Read the computed style of the element rather than the value from the style attribute. This will pick up the style value that you set in your CSS file, so that you don't have to use inline styles.

    Simply change

    var content = document.getElementById(value).style.display;
    

    to

    var content = window.getComputedStyle(document.getElementById(value))["display"];
    
  3. Use an HTML5 data attribute to store information about wether the element is hidden or shown. This is probably semantically the best solution. Firstly, add the data attribute to your HTML element:

     <span id="hide-horarios" data-hidden="yes">
    

    Next, check the data-hidden attribute in your Javascript, instead of the style attribute:

    var content = document.getElementById(value).getAttribute("data-hidden");
    

    Now, you can check that. If you're using this solution, ensure that you check for your data-hidden value instead of none in your if statement - this can be anything that you want. In this example, we would do:

    if (content == "yes") {
        ...
    }
    

    Finally, we'll need to set the data attribute after each change. We can do this by running the following code in the if and else statements respectively:

    document.getElementById(value).setAttribute("data-hidden","no") //goes in if statement
    

    and

    document.getElementById(value).setAttribute("data-hidden","yes") //goes in else statement
    
  4. Or, just simply flip around the if statement conditional:

    if (content != "block") {
        ...
    }
    

    (thanks to @nnnnnn in the comments)

3 Comments

The style object exists, however its display property hasn't been set. ;-)
Thanks for the reply, adeneo told me it in the comments of the principal post like you said there's no information to JS. And I tried (and it worked) just: if(content == "none" || content == "") I think it's the best solution and prevents the inline code (I hate it haha).
@RobG That's what I meant, I was just rushing to answer the question :P Fixing it now.

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.