skip to Main Content

I have a table of members created by a v-for and some users can manage other members based on their role. I implemanted some check to prevent some role to intervene but the complete list of check is done in the backend.

Managing is done with a v-select and I want to be able to revert the v-select choice is the user was not authorized to perform this action.

This was what I made at first:

<template>
  <tr v-for="member in members" :key="member.username">
    <td>{{ member.username }}</td>
    <td>
      <v-select
        density="compact"
        hide-details="true"
        v-model="member.role"
        :items="dialog_roles"
        :item-props="itemProps"
        @update:modelValue="changeRole(member)"
      ></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) {
          //make API call to change the role
          //if it was unauthorized, change back the role in the v-select
        },
    }
  }
</script>

In order to be able to get the old and new value when updating the v-select I moved from v-model="member.role" to a simple :value=member.role.role which then give @update:modelValue="changeRole(member, $event)" where member store the initial value and $event the updated one.

Now that I have that, how do I apply this change if the API call is effective, and how do I revert it if it’s not ?

2

Answers


  1. To apply the change if the API call is effective and revert it if it’s not, you can update the changeRole method in 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 old role
          member.role.role = newRole; // Update the local data immediately
    
          // Make an API call to change the role
          try {
            // Example: If your API call returns an error, you can handle it here
            // 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>
    
    Login or Signup to reply.
  2. first you also need to pass the index in your for loop. it’s important to be able to update the member value later.

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

    you then need to pass the index, to your change role function

    changeRole(member, index)
    

    now within this function you have to cache your values from the latest change.

    // globally defined
    let cachedValues = {
        member: null,
        index: null
    };
    
    changeRole(member, index) {
        cachedValues.member = member;
        cachedValues.index = index
    
        try {
          // make your api call
          // if unauthorized, throw error
        } catch {
          // change back values by taking them from cachedValues
        }
    }
    
    

    If you already want to cache the values from before the change, you can save a whole copy of your members array on state, which is only changed after the submission was successful.

    Example implementation:

    <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'
              },
            },
          ],
          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) {
                try {
                  // make your api call
                  // if unauthorized, throw error
                  // if authorized also adjust cached array and use $set to force reactivity
                  this.$set(this.membersCache, index, member)
                } catch {
                  // change back values by taking them from cachedValues
                  const cachedMember = this.membersCache[index];
                  this.$set(this.members, index, cachedMember)
                }
            }
        }
      }
    </script>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search