Search code examples
htmljquery

Open and close accordion on click a link using jQuery


I am trying to open and close an accordion through a link. I am using jQuery.

You can see the fiddle here - https://jsfiddle.net/squidraj/x1epjfv7/11/

The accordion works well if I just click the panel.

Steps to reproduce the issue:

  1. Click the "Read more title 1" link - it will open the "Title 1" box
  2. Click the "Title 1" box to close the panel - The toggle works well.
  3. Now redo step 1 - Works fine
  4. Redo step 2 - The panel doesn't close, which is the issue. It works when I click the panel second time.

$("a.button").on("click", function(e) {
  e.preventDefault();

  $(".accordion-wrapper div:nth-child(1) article").attr('style', 'max-height:inherit;');
  $(".accordion-wrapper input[id=1]").attr('checked', true);
});

//Closing the accordion

$(".accordion-wrapper label").on("click", function(e){
        const next = $(this).next()[0];
        if (next.style.maxHeight) {
            next.style.maxHeight = "";
        }
 });  
div input {
  display: none;
}
.accordion-wrapper{
  margin: 2rem 0;
  div{
    margin: 1rem 0;
  }
}
.accordion-wrapper article{
 background: rgba(255, 255, 255, 0.25);
 overflow: hidden;
 max-height: 0px;
 position: relative;
 transition: max-height 0.3s ease-in-out;
 border: 1px solid #eee;
 padding: 0 15px;
}

.accordion-wrapper label {
    position: relative;
    display: block;
    cursor: pointer;
    color: #777;
    font-size: 1.1em;
    background: #eeeeee;
    margin: 0;
    padding: 10px 15px;
    border: 1px solid #eee;
    border-bottom: 1px solid transparent;
}

.accordion-wrapper input:checked ~ article{
  max-height: inherit;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<a href="1" class="button">Read more title 1</a>

<div class="accordion-wrapper">
  <div>
    <input id="1" name="test" type="checkbox">
    <label for="1">Title 1</label>
    <article>
      <p>Content 1</p>
    </article>
  </div>
    <div>
    <input id="2" name="test" type="checkbox">
    <label for="2">Title 2</label>
    <article>
      <p>Content 2</p>
    </article>
  </div>
</div>

It seems the state of the hidden checkbox is still unchecked (false), and hence, the panel doesn't close on step 4.


Solution

  • I have managed to fix the issue by using .prop() instead of .attr().

    Here is a detailed explanation why it didn't work with .attr()

    .attr()

    • .attr() stands for attribute and it is used to get or set the value of an attribute of an HTML element.

    • It operates on the attributes as they are defined in the HTML markup.

    • It works with attributes like src, href, title, alt, class, etc.

    • When used to set an attribute's value, it modifies the HTML markup directly.

    • It works with both standard HTML attributes and custom attributes. Example: $("img").attr("src", "newimage.jpg");

    .prop():

    • .prop() stands for property and it is used to get or set the value of properties of HTML elements.
    • It operates on the properties of the DOM element, not directly on the HTML markup.
    • It works with properties like checked, disabled, selected, readOnly, etc.
    • When used to set a property's value, it manipulates the underlying DOM property, not the HTML markup.
    • It typically works with boolean properties or properties that represent the state of an element.
    • Example: $("input[type='checkbox']").prop("checked", true);

    $("a.button").on("click", function(e) {
      e.preventDefault();
      $(".accordion-wrapper div input[id=1]~article").attr('style', 'max-height:inherit;');
      $(`.accordion-wrapper input[id=${$(this).data('id')}]`).prop('checked', true);
    });
    
    //Closing the accordion
    
    $(".accordion-wrapper label").on("click", function(e){
            const next = $(this).next()[0];
            if (next.style.maxHeight) {
                next.style.maxHeight = "";
            }
     });   
    div input {
      display: none;
    }
    .accordion-wrapper{
      margin: 2rem 0;
      div{
        margin: 1rem 0;
      }
    }
    .accordion-wrapper article{
     background: rgba(255, 255, 255, 0.25);
     overflow: hidden;
     max-height: 0px;
     position: relative;
     transition: max-height 0.3s ease-in-out;
     border: 1px solid #eee;
     padding: 0 15px;
    }
    
    .accordion-wrapper label {
        position: relative;
        display: block;
        cursor: pointer;
        color: #777;
        font-size: 1.1em;
        background: #eeeeee;
        margin: 0;
        padding: 10px 15px;
        border: 1px solid #eee;
        border-bottom: 1px solid transparent;
    }
    
    .accordion-wrapper input:checked ~ article{
      max-height: inherit;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
    <a href="1" data-id="1" class="button">Read more title 1</a>
    
    <div class="accordion-wrapper">
      <div>
        <input id="1" name="test" type="checkbox">
        <label for="1">Title 1</label>
        <article>
          <p>Content 1</p>
        </article>
      </div>
        <div>
        <input id="2" name="test" type="checkbox">
        <label for="2">Title 2</label>
        <article>
          <p>Content 2</p>
        </article>
      </div>
    </div>