Controlling the v-model value of a v-select within a v-for loop

I have set up a table of members using a v-for loop, and certain users have the ability to manage other members based on their role. I have implemented some checks to prevent unauthorized roles from intervening, but the full list of checks is carried out on the backend.

The management feature is facilitated through a v-select element, and I would like to be able to revert the selection made in the v-select if the user is not authorized to perform that action.

This was my initial approach:

<template>
  <tr v-for="member in members" :key="member.username">
    <td>{{ member.username }}</td>
    <td>
      <v-select
        density="compact"
        hide-details="true"
        :value="member.role.role"
        :items="dialog_roles"
        :item-props="itemProps"
        @update:modelValue="changeRole(member, $event)"
      ></v-select>
    </td>
</template>

<script>
  export default {
    data: () => ({
      members: [
        {
          username: 'John',
          role: {
            role: 'owner',
            description: 'full access to the project, can delete it and can manage members'
          },
        },
        {
          username: 'Jane',
          role: {
            role: 'manager',
            description: 'full access to the project, and can manage members'
          },
        },
        {
          username: 'Joe',
          role: {
            role: 'collaborator',
            description: 'can view the project but not modify any content'
          },
        },
      ],
      dialog_roles: [
              {
                "role": "owner",
                "description": "full access to the project, can delete it and can manage members"
              },
              {
                "role": "manager",
                "description": "full access to the project, and can manage members"
              },
              {
                "role": "contributor",
                "description": "full access to the project, but cannot delete it"
              },
              {
                "role": "collaborator",
                "description": "can view the project but not modify any content"
              }
            ]
    }),
    methods: {
        itemProps(item) {
          return {
            title: item.role,
            subtitle: item.description,
          };
        },
        changeRole(member, event) {
          // make API call to change the role
          // if unauthorized, revert back to the initial role
        },
    }
  }
</script>

To have access to both the old and new values when updating the v-select, I replaced v-model="member.role" with a simple :value=member.role.role. This allows for

@update:modelValue="changeRole(member, $event)"
, where member stores the initial value and $event holds the updated one.

Now that I have this setup, the question is how do I implement the change if the API call is successful, and how do I revert it if not?

Answer №1

If you want to implement a feature where the API call is applied if successful and reverted if it fails, you can make modifications to the changeRole function within your Vue component.

<template>
  <tr v-for="member in members" :key="member.username">
    <td>{{ member.username }}</td>
    <td>
      <v-select
        density="compact"
        hide-details="true"
        :value="member.role.role"  <!-- Use :value to bind the role.role value -->
        :items="dialog_roles"
        :item-props="itemProps"
        @update:modelValue="changeRole(member, $event)"
      ></v-select>
    </td>
  </tr>
</template>

<script>
export default {
  data: () => ({
    // Your data here
  }),
  methods: {
    // ...

    async changeRole(member, newRole) {
      const oldRole = member.role.role; // Store the previous role
      member.role.role = newRole; // Update the local data immediately

      // Perform an API call to change the role
      try {
        // Example: Handle errors returned by the API call
        // if (response.error) {
        //   member.role.role = oldRole; // Revert the role
        //   console.error('API call failed. Reverted role.');
        // }
      } catch (error) {
        // Handle API call errors here
        console.error('API call failed. Reverted role.');
        member.role.role = oldRole; // Revert the role
      }
    },
  },
};
</script>

Answer №2

To ensure the index is passed in your for loop, it is crucial for updating member values later on.

 <tr v-for="(member, index) in members" :key="member.username"

When calling the change role function, remember to include the index.

changeRole(member, index)

Within the changeRole function, store the latest values before any updates are made.

// Global variable
let cachedValues = {
    member: null,
    index: null
};

changeRole(member, index) {
    cachedValues.member = member;
    cachedValues.index = index

    try {
      // Perform API call
      // If unauthorized, throw an error
    } catch {
      // Revert values back to cachedValues
    }
}

If you wish to save values before changes, consider storing a copy of the members array in the state, which is only updated after successful submission.

Sample implementation:

<script>
  export default {
    data: () => ({
      autoChange: false,
      members: [
        {
          username: 'John',
          role: {
            role: 'owner',
            description: 'full access to the project, can delete it and can manage members'
          },
        },
        {
          username: 'Jane',
          role: {
            role: 'manager',
            description: 'full access to the project, and can manage members'
          },
        },
        {
          username: 'Joe',
          role: {
            role: 'collaborator',
            description: 'can view the project but not modify any content'
          },
        },
      ],
      membersCache: [
        {
          username: 'John',
          role: {
            role: 'owner',
            description: 'full access to the project, can delete it and can manage members'
          },
        },
        {
          username: 'Jane',
          role: {
            role: 'manager',
            description: 'full access to the project, and can manage members'
          },
        },
        {
          username: 'Joe',
          role: {
            role: 'collaborator',
            description: 'can view the project but not modify any content'
          },
        },
      ],
    }),
    methods: {
        itemProps(item) {
          return {
            title: item.role,
            subtitle: item.description,
          };
        },
        changeRole(member, index) {
            if (this.autoChange) return;
            try {
              // Make API call
              // If unauthorized, throw error
              // If authorized, update cached array and force reactivity using $set
              this.$set(this.membersCache, index, member)
            } catch {
              // Revert values back to cachedValues
              const cachedMember = this.membersCache[index];
              this.autoChange = true;
              this.$set(this.members, index, cachedMember);
              const timeoutMs = 500;
              setTimeout(() => {
                this.autoChange = false;
              }, timeoutMs);
            }
        }
    }
  }
</script>

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

javascript: verify the presence of uppercase and lowercase letters

Can the validation of at least 2 lowercase and 2 uppercase letters be implemented when checking the case? Below is the condition I am currently using. function HasMixedCase(passwd){ if(passwd.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)) return true ...

Designing a photo frame slider for a unique touch

My skills in javascript and jQuery are limited, but I am looking to create a customizable slider. While exploring options like Flexslider (), I found it challenging to meet the following specifications: Eliminate color gaps between thumbnails Enable thu ...

Adding .js extension to relative imports in TypeScript compilation for ES6 modules

This particular issue may appear simple at first glance, but determining the required settings/configurations to resolve it is not straightforward. Below are the directory structure and source code for a Hello World program: Directory Structure: | -- Hel ...

Struggling with my jQuery Ajax call, need some help

I am attempting to create an ajax request that will update the content of my select element. Below is the code for my request : $(function() { $("#client").change(function() { type: 'GET', url: "jsonContacts. ...

What are the potential causes of receiving the error message "No Data Received ERR_EMPTY_RESPONSE"?

I often encounter this issue on my website, especially when I have a thread open. It seems to happen whenever I am actively checking for new posts and notifications via Ajax every 10 seconds or so. However, I'm not sure if this continuous reloading is ...

External IPs cannot access Node.js

I am facing an issue with my Amazon EC2 Server where I have set up a node js server. It is not accessible from the outside using the public DNS, but it can be accessed from the same instance (localhost). Any assistance in resolving this problem would be gr ...

bespoke theme background hue

I currently have material-ui@next installed and I am attempting to customize the background color of the theme. Here is what I have tried: const customizedTheme = createMuiTheme({ palette: createPalette({ type: 'light', primary: purple ...

jQuery causing trouble with AJAX in Rails

Currently, I am fetching a list of users from the controller side and generating the HTML code to append it. This is how I wrote the code: $.ajax({ type : "get", contentType : "application/json; charset=utf-8", url : "/users/sear ...

Can you explain the distinctions between Vue JS and React JS?

As I delve into learning Vue Js and React Js, my search for a detailed comparison between the two on Google left me unsatisfied. I came across resources answering the singular questions "What is Vue js?" and "What is React Js," but none that directly comp ...

Error in HTML: Text variable is not displaying the number value

Currently, I am facing a challenge with my code. I have a variable named "Timer" that I want to increment by one and then display the number. However, I am unable to see the "Test Successful!" message displayed on the screen. Surprisingly, there are no e ...

Reactjs Invariant Violation caused by the npm package (react-loader)

I'm currently attempting to integrate react-loader into my react component. This is the code snippet I'm using: /** @jsx React.DOM */ var Loader = require('react-loader'); var DisplayController = React.createClass({ // etc ...

Is there a way to prevent the slide-out bar from automatically hiding when selecting an item from its list?

I am facing an issue with my dashboard that has a slideout sidebar. Whenever I press the toggle button, the sidebar slides out as expected. However, when I click on any tab within the sidebar, it hides again. I only want it to hide when toggled. My code is ...

Transform an array of strings into properties of an object

Looking for a way to map an array to a state object in React? Here's an example: const array =["king", "henry", "died", "while", "drinking", "chocolate", "milk"] Assuming you have the following initial state: state = { options:{} } You can achieve ...

Selecting the quartile value for every individual data point

I am currently graphing the sentiment values of tweets over a span of 10 years. The CSV file contains three columns as outlined below. Successfully, I managed to plot each value by date. However, upon attempting to create an area graph, I encountered an i ...

The dialogue box fails to appear when accessed from the dropdown menu shadcn

I'm encountering an issue while using nextJS with shadcn. I am attempting to open a dialog from a dropdown menu, but instead of opening, it just closes the dropdown menu. My assumption is that I either need to utilize ref and states or position the al ...

Gatsby's own domain and absolute links: the perfect pair

My goal is to establish a direct link to files (such as images and downloads) in my static directory. During development, the link should be http://localhost/myimage.jpg, and once deployed, it needs to switch to https://www.example.com/myimage.jpg. Is the ...

Using CasperJS, learn how to effectively utilize the jQuery find() function

I'm looking to implement something similar to Cabybara within a function in CasperJS. My goal is to select parent divs and extract text from their child elements. Here's an example of what I want: $('div.education').find('h4&apos ...

Why is it possible to import the Vue.js source directly, but not the module itself?

The subsequent HTML code <!DOCTYPE html> <html lang="en"> <body> Greeting shown below: <div id="time"> {{greetings}} </div> <script src='bundle.js'></script& ...

Issues with Thunderbird not displaying copied HTML emails

Hello there amazing people at Stackoverflow. I need some assistance with HTML formatting. I am currently working on a bootstrap modal that is being dynamically modified through jQuery using the append() function. Check out the code snippet below: <div ...

Can React Slick be configured to display a Carousel within another Carousel?

Can React Slick support a Carousel within another Carousel? import Slider from "react-slick"; <Slider {...settings} > <div/> <div> <Slider {...settings} > ...