Is there a way to instantly show the contents of a newly opened tab in BootstrapVue?

Good day,

my objective is as follows:

Whenever a new tab is opened, it should become 'active' and display its content on the browser

  • Issue: Currently, when a new tab is opened, the previous tab remains 'active'.

Check out a simple example of this problem.

To replicate this issue, follow these steps:

  1. Go to the BootstrapVue Playground;
  2. Scroll down to the 'Dynamic tabs + tabs-end slot' section at the bottom of the page (within the advanced examples);
  3. Double-click on the code area (to enable editing);
  4. Paste the code snippet below
<template>
  <div>
    <b-card no-body>
      <b-tabs card>
        <!-- Render Tabs, provide a unique `key` to each tab -->
        <b-tab v-for="tab in tabs" :key="tab.id" :class="{active:tab.isActive}" :title="'Tab ' + tab.id">
          Tab content {{ tab.id }}
          <b-button size="sm" variant="danger" class="float-right" @click="closeTab(tab.id)">
            Close tab
          </b-button>
        </b-tab>

        <!-- New Tab Button (Using tabs-end slot) -->
        <template v-slot:tabs-end>
          <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
        </template>

        <!-- Display this if no tabs are open -->
        <template v-slot:empty>
          <div class="text-center text-muted">
            No tabs are currently open<br>
            Click the <b>+</b> button above to open a new tab.
          </div>
        </template>
      </b-tabs>
    </b-card>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        tabs: [],
        tabCounter: 0,
        activeTab: {}
      }
    },
    methods: {
      closeTab(x) {
        for (let i = 0; i < this.tabs.length; i++) {
          if (this.tabs[i].id === x) {
            this.tabs.splice(i, 1)
          }
        }
      },
      newTab() {
        const newTab = {
          id: this.tabCounter,
          isActive: true
        };
        this.tabCounter++;
        this.tabs.push(newTab);
        this.setActive(newTab);
      },
      setActive(tab) {
        tab.isActive = true;
        this.activeTab = tab;
        this.tabs.forEach((tab) => {
          if (tab.id !== this.activeTab.id) {
            tab.isActive = false;
          }
        })
      }
    }
  }
</script>
  1. Click on the '+' button in the rendering area at the beginning of the code to add new tabs.

Any ideas on how to fix this issue?

Answer №1

Implement b-tabs component

  1. Action: updated
  2. Attribute: active-tab
<b-tabs active-tab="tabSelected" @updated="onTabUpdated">

data() {
  return {
    tabSelected: 0,
    tabs:[],
  }

onTabUpdated() {
  this.tabSelected = this.tabs.length - 1;
},

Answer №2

To make the newly created tab active, simply add the active prop to <b-tab>.

<b-tab active ...>

Check out this Example

new Vue({
  el: "#app",
  data() {
    return {
      tabs: [],
      tabCounter: 0
    }
  },
  methods: {
    closeTab(x) {
      for (let i = 0; i < this.tabs.length; i++) {
        if (this.tabs[i] === x) {
          this.tabs.splice(i, 1)
        }
      }
    },
    newTab() {
      this.tabs.push(this.tabCounter++)
    }
  }
});
<link href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ec8e8383989f989e8d9cacd8c2d9c2de">[email protected]</a>/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="91f3fefee5e2e5e3f0e1bce7e4f4d1a3bfa0a7bfa1">[email protected]</a>/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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f3919c9c878087819283de858696b3c1ddc2c5ddc3">[email protected]</a>/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-card no-body>
    <b-tabs card>
      <!-- Display Tabs, with unique `key` for each tab -->
      <b-tab v-for="i in tabs" :key="'dyn-tab-' + i" :title="'Tab ' + i" active>
        Tab contents {{ i }}
        <b-button size="sm" variant="danger" class="float-right" @click="closeTab(i)">
          Close tab
        </b-button>
      </b-tab>

      <!-- Button for New Tab (Using tabs-end slot) -->
      <template v-slot:tabs-end>
        <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
      </template>

      <!-- Message when there are no tabs -->
      <template v-slot:empty>
        <div class="text-center text-muted">
          No open tabs<br>
          Click the <b>+</b> button above to open a new tab.
        </div>
      </template>
    </b-tabs>
  </b-card>
</div>

Answer №3

Hello MIchele Rosito,

The b-tabs component requires a value, which is the selected tab index (pass it through v-model)

Here is a simplified version of a functional prototype that I believe accomplishes what you need.

However, there is a caveat. When adding a new tab, it will be rendered by Bootstrap on the (virtual) DOM, which takes some time. We cannot select a tab that has not been rendered yet.

The "solution" (not an ideal workaround) is to wait a few milliseconds before changing the "tabIndex" to allow time for the tab to render.

While not the optimal production solution, I hope this can guide you in the right direction.

<template>
  <div>
    <b-card no-body>
      <b-tabs card v-model="tabIndex">
        <!-- Render Tabs, provide a unique `key` to each tab -->
        <b-tab v-for="tab in tabs" :key="tab.id" :class="{active:tab.isActive}" :title="'Tab ' + tab.id">
          Tab contents {{ tab.id }}
          <b-button size="sm" variant="danger" class="float-right" @click="closeTab(tab.id)">
            Close tab
          </b-button>
        </b-tab>

        <!-- New Tab Button (Using tabs-end slot) -->
        <template v-slot:tabs-end>
          <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
        </template>

        <!-- Render this if no tabs -->
        <template v-slot:empty>
          <div class="text-center text-muted">
            There are no open tabs<br>
            Open a new tab using the <b>+</b> button above.
          </div>
        </template>
      </b-tabs>
    </b-card>
 </div>
</template>

<script>
  export default {
    data() {
      return {
        tabs: [],
        tabIndex: 0,
        tabCounter: 0,
        activeTab: {}
      }
    },
    methods: {
      closeTab(x) {
        for (let i = 0; i < this.tabs.length; i++) {
          if (this.tabs[i].id === x) {
            this.tabs.splice(i, 1)
          }
        }
      },
      newTab() {
        const newTab = {
          id: this.tabCounter,
        };
        this.tabCounter++;
        this.$set(this, tabs, this.tabs.push(newTab));  
        setTimeout(() => { this.tabIndex = this.tabs.length;}, 100);      
      }
    }
  }
</script>

Did you find this information useful?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Activate watch function upon Vue component mounting

Below is a vue component that I want to watch for triggering when it gets mounted. Can you guide me on how to achieve this? Vue.component('check-mark', { name: 'check-mark', template: `<input :value="value"/>`, pro ...

Establish a new <section> to serve as a distinct webpage

I have a question about creating multiple <section> elements on a page. I am looking to build an HTML document with several <section> tags, as outlined below. <html> <head> </head> <body> <sectio ...

Does element.click() in Protractor's Webdriver method return a promise, or is there a way for it to handle errors?

Is the element(by.css()).click() method returning a promise, or is there a way to catch and assert against any errors that may occur? In my scenario, I have a component that is not clickable, and I want to handle the error when this happens. I also want t ...

Can the order of React lifecycle events be reliably predicted across different components?

Is there a clear documentation on the guarantees of React lifecycle order across separate components? For instance, if I have: <div>{ x ? <A /> : <B /> }</div> When x changes from true to false, one component will unmount and the ...

Flipping the order of elements in an array using JavaScript as described in the

While I am aware there are simpler methods to reverse arrays in JavaScript, I am seeking assistance to fully understand how this particular reverse method works. Your help in clarifying this is greatly appreciated. function reverseArrayInPlace(array) ...

A step-by-step guide on how to verify a selection using JavaScript

Is it possible to validate the select option with JavaScript? For example, if a user selects "Admin," then the page works for admin login. If they select "Vendor," then it works for vendor login. <table class="login_table" width="100%" border="0" cells ...

Some images fail to load on Ember in the production environment

I am facing an issue with my Ember-cli 1.13 application where all images are loading correctly except those in a specific component. The component is named "list-item" and is defined as follows: {{list-item url="list-url" name="List Name" price="240"}} I ...

Display information using an ASP.Net barcode scanner

Currently, I am developing a WCF service application that involves receiving characters from a barcode reader and displaying the data on the UI for the user. My issue arises when inputting data using the keyboard into a textbox; everything functions corr ...

How can I utilize this.$apollo within a Vuex store using vue-apollo in a NUXT environment?

I am trying to save the user data from a login action in the vuex store, but I am unable to access this.$apollo. export const actions = { UPSERT_USER({ commit }, { authUser, claims }) { this.$apollo .mutate({ mutation: UPSERT_USER ...

Fill the input field with data retrieved from a json file

I'm working on a Rails app where I need to populate a field with a value from JSON that is returned after clicking on a link. Can anyone point me to a tutorial that explains how to use Ajax correctly for this purpose? Here's my plan: 1. Send a G ...

What is the best way to refresh a webpage in Vue.js following a specific event or a button click?

Is there a way to reload a webpage only once after clicking a button, without the need for auto-refreshing at set intervals? I've written my code in Vue.js. Can anyone offer guidance on how to accomplish this? Any assistance would be greatly apprecia ...

Having Trouble with Imported JavaScript File in Astro

Why isn't the js file working in Astro when I try to import or add a source in the Astro file? For example: <script src="../scripts/local.js"></script> or <script>import '../scripts/local.js'</script> I am ...

Broaden the reach of the ajax .done function to encompass the surrounding function

It seems like my previous attempts to find a solution for the function below were unsuccessful: function countNoFilters(keyword){ keyword = typeof keyword !== 'undefined' ? keyword : "keyword="+$("#keyword-hidden").val(); var getR ...

Click event triggering smooth scrolling

I am currently working on implementing a smooth scrolling effect using the React JavaScript library without relying on jQuery. My goal is to ensure that when a user clicks on a link, they are directed to the specific section of the page seamlessly. The f ...

What is the process for exporting the reducer function and integrating it into the storeModule.forRoot within an Angular application?

Recently, I started delving into ngrx and decided to educate myself by going through the official documentation on their website ngrx.io. During this exploration, I came across a puzzling piece of code in one of their reducers. The file in question is cou ...

Securing your Angular application with user authentication and route guarding ensures

In the process of developing an Angular single-page application (SPA) front-end that interacts with a GraphQL endpoint, I encountered a challenge. Upon user login, I store the token in local storage and update the authentication state in my AuthService com ...

Is there a way to assess Python code within a document's context using JavaScript in JupyterLab?

When using Jupyter Notebooks, I can create a cell with the following JavaScript code: %%javascript IPython.notebook.kernel.execute('x = 42') After executing this code, in another cell containing Python code, the variable x will be bound to 42 a ...

Closing tag in jQuery

In my script, I am using a div tag within the jquery code. However, whenever the div tag appears in the jquery code, it automatically closes the script tag and breaks the jquery code. For example, consider the following code: <script>var b = 25;var ...

Validating a string using regular expressions in JavaScript

Input needed: A string that specifies the range of ZIP codes the user intends to use. Examples: If the user wants to use all zip codes from 1000 to 1200: They should enter 1000:1200 If they want to use only ZIP codes 1000 and 1200: They should enter ...

What is the technique for incorporating FontAwesome icons onto an HTML 5 canvas?

I am encountering an issue while trying to use FontAwesome icons within my HTML 5 canvas. Here is what I have attempted: ct.fillStyle = "black"; ct.font = "20px Font Awesome"; ct.textAlign = "center"; var h = 'F1E2'; ct.fillText(String.fromCha ...