Search code examples
vue.jsvuejs2vuejs3

VueJS make a all components collapse not only one


I have a question regarding this code:

<div id="foo">

</div>

<script type="text/x-template" id="collapsible">
    <div class="wrapper">
    <div class="header" v-on:click="collapsed = !collapsed">
      <p> original : ""</p>
    
    </div>
    
    <div class="collapsible" v-show="!collapsed">1111</div>

    </div>
</script>


<script type="text/x-template" id="app">
<div>
    <button v-on:click="collapseAll">Collapse All</button>
    <button v-on:click="expandAll">Expand All</button>
        
   <div class="wrapper"> 
    <collapsible ref="collapsible" >
        </collapsible>
       

  <div  v-for="question in questions"  v-bind:key="question">
       <p 
          :class="question.is_answered ? 'header_answered' : 'header'"
          v-on:click="collapsed = !collapsed" 
          >
          {{ question.question_id}} - {{ question.question_title}}
        </p> 
       <div 
         class="collapsible"  v-show="!collapsed"                                      v-bind:key="question" v-for="answer in question.answers">
          <p>{{answer.answer_title}}</p>
        
      </div>
  </div> <!-- .questions --> 
     </div> <!-- .wrapper --> 
        </div> <!-- .wrapper --> 
 
</script>
<div id="foo">

</div>

<script type="text/x-template" id="collapsible">
    <div class="wrapper">
    <div class="header" v-on:click="collapsed = !collapsed">
      <p> original : ""</p>
    
    </div>
    
    <div class="collapsible" v-show="!collapsed">1111</div>

    </div>
</script>


<script type="text/x-template" id="app">
<div>
    <button v-on:click="collapseAll">Collapse All</button>
    <button v-on:click="expandAll">Expand All</button>
        
   <div class="wrapper"> 
    <collapsible ref="collapsible" >
        </collapsible>
       

  <div  v-for="question in questions"  v-bind:key="question">
       <p 
          :class="question.is_answered ? 'header_answered' : 'header'"
          v-on:click="collapsed = !collapsed" 
          >
          {{ question.question_id}} - {{ question.question_title}}
        </p> 
       <div 
         class="collapsible"  v-show="!collapsed"                                      v-bind:key="question" v-for="answer in question.answers">
          <p>{{answer.answer_title}}</p>
        
      </div>
  </div> <!-- .questions --> 
     </div> <!-- .wrapper --> 
        </div> <!-- .main --> 
 
</script>

it can be see how it works in this codepen:

https://codepen.io/P-Mart/pen/vYPmLbr

the problem is that I want to make collapsible only one question. When a question is clicked shall shown the answers. The problem is that all questions are shown. Could you please help me? what I am doing wrong?

Thank you in advance.


Solution

  • The collapsed variable is a single variable shared by all questions, so that's why changing it's value affects all questions. You need to have a collapsed property on each question so they can expand/collapse independently of each other.

    questions: [
      {
        collapsed: true,
        question_id: "52",
        ...
      },
      {
        collapsed: true,
        question_id: "53",
        ...
      },
      {
        collapsed: true,
        question_id: "54",
        ...
      },
    
    collapseAll(){
      this.questions.forEach(q => q.collapsed = true)
    },
    expandAll(){
      this.questions.forEach(q => q.collapsed = false)
    },
    
      <div  v-for="question in questions"  v-bind:key="question">
           <p 
              :class="question.is_answered ? 'header_answered' : 'header'"
              v-on:click="question.collapsed = !question.collapsed" 
              >
              {{ question.question_id}} - {{ question.question_title}}
            </p> 
           <div 
             class="collapsible"  v-show="!question.collapsed"                                      v-bind:key="question" v-for="answer in question.answers">
              <p>{{answer.answer_title}}</p>
            
          </div>
      </div>
    

    updated codepen