Avoid stopping Bootstrap Vue's events

Need help with a b-form-select control in Bootstrap Vue. Trying to execute a function when the value changes, but want the option to cancel the event and keep the original value.

Complicating matters, the select is in a child component while the function is in the parent component.

The child component

public values: any[] = [
  { name: 'default'},
  { name: 'forbidden'},
  { name: 'other option' },
]

<b-form-select :value="property" @change="$emit('onPropertyChange', arguments[0])">
   <option v-for="(val, key) in values" :value="val" :key="key">{{val.Name}}</option>
</b-form-select>

The parent component:

this.property = { name: 'default' }
public onPropertyChange(newValue) {
  if (newValue.name === 'forbidden') {
    // Not changing this.property
  } else {
    // Changing it
    this.property = newValue
  }     
}

<child :property="property" @onPropertyChange="onPropertyChange"></child>

After selecting 'forbidden' in the select, I notice that the box shows the new value but both properties remain unchanged, which is desired. How do I prevent the select from updating as well?

Bootstrap Vue seems lacking a prevent modifier for change events. Even using the native event leads to the same issue.

Is my approach incorrect?

Answer №1

Enhancing user experience by disabling forbidden options instead of allowing selection confusion can be achieved through a change event handler. By saving and restoring the old value using nextTick, the desired behavior can be implemented.

It is important to note that the structure of your options may not align with b-form-select. To address this, a computed property has been created to generate the correct structure and handle the disabled attribute, which is then used in the b-form-select.

new Vue({
  el: '#app',
  data: {
    selected: 'default',
    options: [{
        name: 'default',
      },
      {
        name: 'forbidden'
      },
      {
        name: 'other option'
      },
      {
        name: 'what I had before'
      },
    ]
  },
  computed: {
    selectOptions() {
      return this.options.map((opt) => ({
        text: opt.name,
        value: opt.name,
        disabled: opt.name === 'forbidden'
      }));
    }
  },
  methods: {
    onChange(newValue) {
      const oldValue = this.selected;

      if (newValue === 'what I had before') {
        this.$nextTick(() => {
          this.selected = oldValue;
        });
      }
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>
<div id="app">

  <b-form-select v-model="selected" :options="selectOptions" @change="onChange">
  </b-form-select>

  <div>Selected: <strong>{{selected}}</strong></div>

</div>

Answer №2

My suggestion involves utilizing $refs and computed getter/setter functions to address the issue at hand, although it can also be accomplished with v-bind/v-on. This approach is particularly beneficial in scenarios where user confirmation is required.

<template>
    <div>
        <b-form-select
            ref="mySelect"
            v-model="choiceHandler"
            :options="selectOptions"
        >
        </b-form-select>
    </div>
</template>
<script>
export default {
    data() {
        return {
            selectOptions: [
                { value: 1, text: "Choice 1" },
                { value: 2, text: "Choice 2" },
                { value: 3, text: "Choice 3" },
            ],
            storedChoice: 3,
        };
    },
    computed: {
        choiceHandler: {
            get() {
                return this.storedChoice;
            },
            set(newValue) {
                this.$refs.typeSelect.localValue = this.storedChoice; 
                let confirmDialog = new Promise((resolve) => {
                    setTimeout(() => {
                        resolve(true);
                    }, 1500);
                });
                confirmDialog.then((res) => {
                    if (res) {
                        this.storedChoice = newValue;
                    } else console.log("No changes");
                });
            },
        },
    },
};
</script>

In order to prevent undesired changes from affecting the data model or store, we employ a setter function. Prior to validation, we revert the localValue of the b-form-select component to its original state. If validation succeeds, the data model is updated, triggering Vue to refresh the b-form-select. Otherwise, no action is taken.

Although this method may result in a Vue warning related to direct DOM manipulation, I believe it is justified in this context. It prevents the browser from displaying data that have not yet been saved in the model, rather than overriding the existing data model.

For an alternative solution using a vanilla <select> tag without BootstrapVue, as well as employing v-bind/v-on instead of getters and setters, please refer to this link.

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

Union does not contain the specified property in Typescript

Here are the types that I have: Foo { foobar: any } Bar { fooBarBar: any; } I want to use a function defined like this: this.api.submit(param: Foo | Bar) When trying to use it, I encountered an issue: this.api.submit(param.foobar) // does no ...

Is it possible to utilize a const as both an object and a type within TypeScript?

In our code, we encountered a scenario where we had a class that needed to serve as both an object and an interface. The class had a cumbersome long name, so we decided to assign it to a constant. However, when we attempted to use this constant, we faced s ...

Rotate object within HTML table

I have a simple data structure as shown below: [ { "ClientId": 512, "ProductId": 7779, "Date": "2019-01-01", "Quantity": 20.5, "Value": 10.5 }, { "ClientId": 512, "ProductId": ...

Incorporate a Vue directive based on a certain condition

Can a directive be set based on a condition? I have a directive called "sticky" that makes elements stick to the screen. I am currently using it in a social share component. <tempalte> <div class="social-share" v-sticky> .... ...

The Angular 9 custom directive is malfunctioning on mobile devices

I recently created a custom directive in Angular 9 that allows users to input only digits and one decimal point. While the directive works perfectly on desktop, it seems not to function at all on mobile devices - almost as if it doesn't exist within t ...

Error encountered while attempting to retrieve an environment variable: Invalid token found

I am currently facing an issue while trying to add an environment variable inside the .env file in my Nuxt project. The version of Nuxt.js I am using is 2.15.3 Below is a snippet from my nuxt.config.js: export default { publicRuntimeConfig: { baseU ...

Refresh a page automatically upon pressing the back button in Angular

I am currently working on an Angular 8 application with over 100 pages (components) that is specifically designed for the Chrome browser. However, I have encountered an issue where the CSS randomly gets distorted when I click the browser's back button ...

Discovering latitude and longitude coordinates from a map URL, then enhancing dynamism by utilizing the coordinates as parameters

Hello, I am currently learning Vue.js and have encountered a challenge with embedding Google Maps URLs. Despite my extensive research on Google, I have not been able to find the solution I need. Here is an example of the URL I am working with: "https: ...

What is the best way to assign table rows to various interfaces in typescript?

Assuming I have the interfaces provided below: export interface IUserRow { id: string, state: string, email: string, } export interface ITableRow { id: string, [key: string]: any; } export type Rows = ITableRow | IUserRow; // additio ...

Encountered an error while attempting to compare 'true' within the ngDoCheck() function in Angular2

Getting Started Greetings! I am a novice in the world of Angular2, Typescript, and StackOverflow.com. I am facing an issue that I hope you can assist me with. I have successfully created a collapse animation for a button using ngOnChanges() when the butto ...

Attribute specified does not belong to type 'DetailedHTMLProps<ButtonHTMLAttributes

I am working on creating a reusable 'button' component and I would like to include a href attribute so that when the button is clicked, it navigates to another page. An Issue Occurred: The following error was encountered: 'The type '{ ...

Deploying Vue.js applications

I am working on a Vue application that was created using vue-cli. It is semi-developed and I would like to show the progress to a customer. Therefore, I am looking to deploy what we have so far. If I execute the script npm run build, will I still be able ...

TypeScript encountered an error with code TS2554, indicating that it was expecting 0 arguments but instead received 1 in an Ionic application

Hello everyone! I'm encountering an issue in my project involving a Type Script error TS2554: Expected 0 arguments, but got 1. This error is preventing me from being able to select other options for custom input pop up. In this forum post, I have shar ...

Styling with Radial Gradients in CSS

Struggling to create a banner with a radial gradient background? I'm almost there, but my code isn't matching the design. Any assistance would be greatly appreciated as I can't seem to get the right colors and only part of the first circle i ...

Apply CSS styles conditionally to an Angular component

Depending on the variable value, I want to change the style of the p-autocomplete component. A toggle input determines whether the variable is true or false. <div class="switch-inner"> <p [ngClass]="{'businessG': !toggle }" clas ...

Alter the Vue view using an object instead of the url router

Currently working on a chrome extension using Vue.js where I need to dynamically update views based on user interactions. Usually, I would rely on the Vue Router to handle this seamlessly... however, the router is tied to the URL which poses limitations. ...

"Utilizing jQuery and Bootstrap 4 in TypeScript, attempting to close modal window using jQuery is not functioning

Trying to make use of jquery to close a bootstrap modal within an angular project using typescript code. The following is the code: function call in html: (click)="populaterfpfromsaved(i, createSaved, createProp)" createSaved and createProp are local ...

Encountering a promise error when using TypeScript and React Lazy

I've been working with React and TypeScript, incorporating a higher order component to verify user authentication. However, after implementing the hoc, I encountered an error in my routes: /home/nidhin/Documents/Nidhinbackup/F/iot-remsys-demotwo/rem ...

Testing vue.js components through vue-loader with dependency injection

I am currently experimenting with testing my Vue.js component using vue-loader, a webpack loader. I tried following the tutorial provided by vue-loader but encountered unexpected issues. Below is the code snippet for my component: <template> <h ...

Lazy-loaded modules in Angular that contain services provided within the module

Currently, I am facing a challenge with lazy-loaded modules and services that are provided in these modules. My folder structure looks like this: app -> featureModule1 (lazy loaded) -> featureModule2 (lazy loaded) -->services --->servi ...