10

In a <b-table> I would like to create an action on each items so I have a button:

<b-table :items="data" :fields="fields">
  <template v-slot:cell(actions)="data">
    <b-button v-on:click="doIt(data.index)">Do It</b-button>
  </template>
</b-table>

Then I have a Form in a sidebar

<b-sidebar id="do-it-form" title="Do it" right>
...
</b-sidebar>

In my methods I would like to respond to the action:

methods: {
    doIt(id) {
        sidebar.form.id = id
        sidebar.show().onSubmit(() => {
           axio...
           refresh(<b-table>)
        })
    }
}

Of course, this last part is not valid. On Bootstrap Vue manual I didn't find how to interact from Vue to Bootstrap components. Any clue?

nowox
  • 25,978
  • 39
  • 143
  • 293

3 Answers3

20

You can emit an event on $root, which can be used to toggle the sidebar. The second parameter being the id of the sidebar you wish to open. this.$root.$emit('bv::toggle::collapse', 'my-sidebar-id')

<b-collapse> and <b-sidebar> listens for the same event, which is why it says collapse in the event.

new Vue({
  el: '#app',
  methods: {
    openSidebar() {
      this.$root.$emit('bv::toggle::collapse', 'my-sidebar')
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.17.1/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.17.1/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-sidebar id="my-sidebar" right>
    My sidebar
  </b-sidebar>

  <b-btn @click="openSidebar">
    Open sidebar
  </b-btn>
</div>

Alternatively you can bind a boolean property to the v-model on the sidebar and set the boolean to true when you want to open the sidebar.

new Vue({
  el: '#app',
  data() {
    return {
      isSidebarOpen: false
    }
  },
  methods: {
    openSidebar() {
      this.isSidebarOpen = true
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.17.1/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.17.1/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-sidebar v-model="isSidebarOpen" right>
    My sidebar
  </b-sidebar>

  <b-btn @click="openSidebar">
    Open sidebar
  </b-btn>
</div>
Hiws
  • 8,230
  • 1
  • 19
  • 36
4

Also, you can use one of the sidebar built-in public methods show, hide or toggle. All you need is add a reference to your sidebar

<b-sidebar ref="mySidebar" id="do-it-form">
...
</b-sidebar>

and then in any of your methods where/when it's needed, you can simply call any of them

this.$refs.mysidebar.show();
this.$refs.mysidebar.hide();
this.$refs.mysidebar.toggle();
Virtual Device
  • 1,650
  • 3
  • 10
  • 26
-1

You can also just assign a boolean value to the visible prop on the b-sidebar component and toggle the boolean value as you like.

<b-sidebar ref="mySidebar" id="do-it-form" :visible="showSidebar">
...
</b-sidebar>

And toggling it:

data: {
   showSidebar: false, //starts off invisible
},
methods: {
   toggleSidebar(){
      this.showSidebar = !this.showSidebar
   }
}

This approach at first glance is not the best in an approach where you have other components updating the sidebar visiblity. This use case is for situations when all updates to the sidebar visibility are made from a central store by using a central boolean value.

e.g.

const state = {
  showSidebar: null
}

const mutations: {
  toggleSidebar(state, payload){
     if (payload) { //payload incase you want to force a value and not just toggle
            state.showSidebar = payload;
     } else {
            state.showSidebar = !state.showSidebar;
     }
  }
}

And in your components:

computed: {
   showSidebar(){
     return this.$store.state.showSidebar
   }, //starts off invisible
},
methods: {
   toggleSidebar(){
      this.$store.commit("toggleSidebar");
   }
}

Your updated sidebar component would look like this:

<b-sidebar ref="mySidebar" id="do-it-form" :visible="showSidebar" @change="updateSidebar">
...
</b-sidebar>

And the method:

methods: {
   updateSidebar(value){
      this.$store.commit("toggleSidebar", value);
   }
}
Pogo
  • 43
  • 9
  • 1
    The issue with this method is you don't have a two-way binding. Meaning if the sidebar is closed by other means (like clicking the `x` inside the sidebar), the property `showSidebar` isn't properly updated. It's better to bind to the `v-model` instead to ensure proper two-way binding. – Hiws Aug 10 '21 at 11:24
  • 1
    @Hiws you're right! Although I should have added that this is an approach for when you have that boolean value in a central place e.g. your state in the vuex store. You can make sure that all events to toggle the sidebar are made to that variable, so there's no non-uniform update to the showSidebar variable. That is actually the use case I had in mind. – Pogo Aug 10 '21 at 11:37
  • 1
    What if you close the sidebar using the `x` button inside the sidebar? Might be worth using the `@change` event to make sure your state is updated in that case. Or using a getter/setter in your computed property, where the `getter` returns `state.showSidebar` and the `setter` commits the new value to your store. And then binding that computed property to the sidebars `v-model` – Hiws Aug 10 '21 at 12:02