javascripttypescriptvue.jsprimevue

How to prevent tab changes in PrimeVue v3 TabView?


I am using PrimeVue V3 TabView with composition API.

Inside each tab I have a form and I want to trigger form validation before switching tabs. So I need to interrupt the tab change, do something (form validation), and then conditionally proceed to the clicked tab.

The TabView docs show 3 events: update:activeIndex, tab-change, and tab-click. But as far as I can tell, all of those are triggered after changing tabs, not before.

Any idea how to go this working?

I found a similar question and answer based on the old Options API but I cannot get it working for Vue 3 Composition API.

Here is a live reproduction on stackblitz.

<template>
  <TabView
    v-model:activeIndex="activeIndex"
    @tab-change="handleTabChange"
    @tab-click="handleTabClick"
  >
    <TabPanel header="Opening Hours"> Opening hours form goes here </TabPanel>
    <TabPanel header="Contacts"> Contacts form goes here </TabPanel>
  </TabView>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import type { TabViewChangeEvent, TabViewClickEvent } from 'primevue/tabview';

const activeIndex = ref();

const handleTabClick = async (event: TabViewClickEvent) => {
  console.log('handleTabClick', event);
  const nextTabIndex = event.index;
  const isValid = false; // Simulated form validation
  if (isValid) {
    // Form is valid, continue with the tab change
    console.log('form valid');
    activeIndex.value = nextTabIndex;
  } else {
    // Form is invalid, do nothing (don't change tabs)
    console.log('form invalid');
  }
};

const handleTabChange = async (event: TabViewChangeEvent) => {
  console.log('handleTabChange', event);
  const nextTabIndex = event.index;
  const isValid = false; // Simulated form validation
  if (isValid) {
    // Form is valid, continue with the tab change
    console.log('form valid');
    activeIndex.value = nextTabIndex;
  } else {
    // Form is invalid, do nothing (don't change tabs)
    console.log('form invalid');
  }
};
</script>

Solution

  • I just made the old Options API answer workable for you

    enter image description here

    Here is the code

    <template>
      <TabView
        v-model:activeIndex="activeIndex"
        @tab-change="handleTabChange"
        @tab-click="handleTabClick"
      >
        <TabPanel header="Opening Hours"> Opening hours form goes here </TabPanel>
        <TabPanel header="Contacts"> Contacts form goes here </TabPanel>
      </TabView>
    </template>
    
    <script setup lang="ts">
    import { ref } from 'vue';
    import TabView from 'primevue/tabview';
    import TabPanel from 'primevue/tabpanel';
    import type { TabViewChangeEvent, TabViewClickEvent } from 'primevue/tabview';
    
    // Override the default onTabClick method of TabView
    // This should ideally be in a global setup file, not in a component
    TabView.methods.onTabClick = function (event, tab, i) {
      this.$emit('tab-click', {
        originalEvent: event,
        tabInfo: tab,
        index: i,
      });
    };
    
    // Ref to keep track of the active tab index
    const activeIndex = ref();
    
    // Handler for tab click events
    const handleTabClick = async (event: TabViewClickEvent) => {
      console.log('handleTabClick', event);
      const nextTabIndex = event.index;
    
      // Simulated form validation
      // In a real scenario, this would be replaced with actual form validation logic
      const isValid = false; 
    
      if (isValid) {
        // If the form is valid, allow the tab change
        console.log('form valid');
        activeIndex.value = nextTabIndex;
      } else {
        // If the form is invalid, prevent the tab change
        console.log('form invalid');
        // No action needed here as we're not changing activeIndex
      }
    };
    
    // Handler for tab change events
    const handleTabChange = async (event: TabViewChangeEvent) => {
      console.log('handleTabChange', event);
      
      // Prevent the default tab change behavior
      event.originalEvent.preventDefault();
    
      const nextTabIndex = event.index;
    
      // Simulated form validation
      // In a real scenario, this would be replaced with actual form validation logic
      const isValid = false; 
    
      if (isValid) {
        // If the form is valid, allow the tab change
        console.log('form valid');
        activeIndex.value = nextTabIndex;
      } else {
        // If the form is invalid, prevent the tab change
        console.log('form invalid');
        // No action needed here as we've already prevented the default behavior
      }
    };
    </script>