ehthreeone
ehthreeone

Reputation: 91

VueJS: how to toggle "collapse" of different components? (if X is show then Y is hide, vice versa)

I'm very new to VueJS and trying to re-engineer an old site into VueJS 2. My first issue is how to replicate what I did in JQuery, where by:

if component X 'display' is true, then component Y 'display' is false, and vice versa.

Essentially, if I click a button to expand the b-collapse "cccollapse" element, then I want the "szcollapse" element to collapse (if it is expanded) and vice versa, so only one of those collapsible elements is "extended" at a given point in time.

I'm using bootstrap-vue in my Vue project and this is what the current template looks like this:

<template>
  <div>
    <b-container fluid class="button-row">
    <fieldset>
      <legend class="scheduler-border">
        <span class="legend-label">YOU : MANAGE YOUR KEYS</span>
        </legend>
        <b-row class="menu-row">
            <b-col>
                <b-button variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-plus-circle"></i>REQUEST A KEY</b-button>
            </b-col>
        </b-row>
        <b-row class="menu-row">
            <b-col>
                <b-button v-b-toggle.szcollapse v-on:click="collapseCCCollapse" variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-share-square"></i>ISSUE A KEY</b-button>
                <b-collapse ref="szcollapse" id="szcollapse" class="mt-2">
                  <b-container class="container-sz-login">
                    <b-row class="cred-dropdown">
                      <b-col>
                        <b-input-group>
                          <span class="input-group-text" id="basic-addon1">
                              <i class="fas fa-user-circle fa-fw"></i>
                          </span>
                          <b-form-input id="txtUsername" />
                        </b-input-group>
                      </b-col>
                    </b-row>
                    <b-row class="cred-dropdown">
                      <b-col>
                        <b-input-group>
                          <span class="input-group-text" id="basic-addon1">
                              <i class="fas fa-lock fa-fw"></i>
                          </span>
                          <b-form-input type="password" id="txtPassword" />
                        </b-input-group>
                      </b-col>
                    </b-row>
                    <b-row class="cred-dropdown">
                      <b-col cols="2"/>
                      <b-col cols="8">
                        <b-button variant="primary" id="szlogin" size="lg" block >LOGIN<i style="padding-left:5px;" class="fas fa-sign-in-alt"></i></b-button>
                      </b-col>
                      <b-col cols="2"/>
                    </b-row>
                  </b-container>
                </b-collapse>
            </b-col>
        </b-row>
        <b-row class="menu-row">
            <b-col>
                <b-button v-b-toggle.cccollapse v-on:click="collapseSZCollapse" variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-network-wired"></i>MANAGE YOUR KEYS</b-button>
                <b-collapse ref="cccollapse" id="cccollapse" class="mt-2" v-model="showCollapse">
                  <b-container class="container-sz-login">
                    <b-row class="cred-dropdown">
                      <b-col>
                        <b-input-group>
                          <span class="input-group-text" id="basic-addon1">
                              <i class="fas fa-user-circle fa-fw"></i>
                          </span>
                          <b-form-input  id="txtCorpId"/>
                        </b-input-group>
                      </b-col>
                    </b-row>
                    <b-row class="cred-dropdown">
                      <b-col>
                        <b-input-group>
                          <span class="input-group-text" id="basic-addon1">
                              <i class="fas fa-lock fa-fw"></i>
                          </span>
                          <b-form-input type="password" id="txtCorpPwd"/>
                        </b-input-group>
                      </b-col>
                    </b-row>
                    <b-row class="cred-dropdown">
                      <b-col cols="2"/>
                      <b-col cols="8">
                        <b-button variant="primary" id="ccLogin" size="lg" block >LOGIN<i style="padding-left:5px;" class="fas fa-sign-in-alt"></i></b-button>
                      </b-col>
                      <b-col cols="2"/>
                    </b-row>
                  </b-container>
                </b-collapse>
            </b-col>
        </b-row>
    </fieldset>
    </b-container>
  </div>
</template>

And this is the script:

<script>
export default {
  name: "Menu",
  props: {
    msg: String
  },
  methods: {
    collapseSZCollapse : function() {
      console.log('this.$refs.szcollapse : ' + this.$refs.szcollapse.collapsed);
    },
    collapseCCCollapse : function() {
      console.log('this.$refs.cccollapse : ' + this.$refs.cccollapse.collapsed)
    }
  },
  data() {
    return {
      showCollapse: false
    };
  }
};
</script>

Obviously the script isnt really doing anything in the methods -- i'm just trying to see how to get the value of the current element to make a decision when v-on:click is called.

What is the correct VueJS way of doing this? I understand (sort of) that vuejs is data driven, but I'm not sure how to get the data from one element to drive the state of the other.

Upvotes: 1

Views: 13033

Answers (2)

nardnob
nardnob

Reputation: 1056

You can give your b-collapse element a v-model binding. Here's a jsfiddle showing an example.

new Vue({
  el: "#app",
  data: {
    firstCollapsed: true,
    secondCollapsed: false
  },
  methods: {
    alternateCollapse() {
      if (this.firstCollapsed) {
      	this.firstCollapsed = false;
        this.secondCollapsed = true;
      } else {
      	this.firstCollapsed = true;
        this.secondCollapsed = false;
      }
    }
  }
});
<div id="app">
  <b-collapse v-model="firstCollapsed" id="collapse1">
    <div>Inner Element 1</div>
  </b-collapse>
  <b-collapse v-model="secondCollapsed" id="collapse2">
    <div>Inner Element 2</div>
  </b-collapse>
  <b-btn @click="alternateCollapse()">Alternate Collapse</b-btn>
</div>

<style scoped>
  .collapse {
    margin: 5px;
    padding: 5px;
    background-color: lightgray;
  }

  #collapse1 {
    border: 1px solid red;
  }
  
  #collapse2 {
    border: 1px solid blue;
  }
</style>

Upvotes: 2

ehthreeone
ehthreeone

Reputation: 91

Sigh. If I had actually investigated properly...

https://bootstrap-vue.js.org/docs/components/collapse/#accordion-support

This does exactly what I want.

Still happy to hear other programmatic answers if there are any?

Upvotes: 4

Related Questions