skip to Main Content

I am trying to scroll through different options that are stored in an array, by using the function below and passing it the correct parameters. But no matter what syntax I try, it doesn’t seem to work.

This is my array and the ref variable i use:

const clothingTypes = ['blazerAndShirt', 'blazerAndSweater', 'collarAndSweater', 'graphicShirt'];
const selectedClothingType = ref(clothingTypes[0]);

I have tried calling the following function in two different ways:

const nextType = (array, refVariable) => {
    const currentIndex = array.indexOf(refVariable.value);
    const nextIndex = (currentIndex + 1) % array.length;
    refVariable.value = array[nextIndex];
};
@click="() => nextType(clothingTypes, selectedClothingType)"

and

@click="nextType(clothingTypes, selectedClothingType)"

But I get the same error in console:

Uncaught TypeError: can’t assign to property "value" on "blazerAndShirt": not an object

What is the correct syntax?

3

Answers


  1. Your error is due to the parameters you pass to your function.
    When calling nextType(clothingTypes, selectedClothingType) from the vue template, the ref are unwrapped. That means you don’t pass in the ref, but the string value directly:

    // clothingTypes === 'blazerAndShirt'
    function nextType(clothingTypes, selectedClothingType) {
      // so it ends up doing
      'blazerAndShirt'.value = array[nextIndex];
      // which is not possible.
    }
    

    Here is a better and simpler approach to your problem: store the current index of the element you want to show.

    const clothingTypes = ['blazerAndShirt', 'blazerAndSweater', 'collarAndSweater', 'graphicShirt'];
    const currentItemIndex = ref(0)
    
    function nextItem() {
      currentItemIndex = (currentItemIndex + 1) % clothingTypes.length
    }
    
    const currentItem = computed(() => clothingTypes[currentItemIndex])
    

    In the template, just do:

    @click="nextItem"
    

    And it will automatically update the computed property currentItem, that you can use in your template.

    Login or Signup to reply.
  2. Unfortunately Vue unwrap refs in a template so its value passed as argument rather than the ref itself, you can use an utility to fix that:

    See on Vue SFC Playground

    import { ref, computed } from "vue"
    
    export default function(val){
      const value = ref(val);
      return computed({
        get: () => value,
        set: v => value.value = v
      });
    }
    

    Usage:

    <script setup>
    import unwrappedRef from './UnwrappedRef';
    const clothingTypes = ['blazerAndShirt', 'blazerAndSweater', 'collarAndSweater', 'graphicShirt'];
    const selectedClothingType = unwrappedRef(clothingTypes[0]);
    
    const nextType = (array, refVariable) => {
        const currentIndex = array.indexOf(refVariable.value);
        const nextIndex = (currentIndex + 1) % array.length;
        refVariable.value = array[nextIndex];
    };
    </script>
    
    <template>
      <div>{{ selectedClothingType }}</div>
      <button @click="nextType(clothingTypes, selectedClothingType)">Click me</button>
    </template>
    
    
    Login or Signup to reply.
  3. I don’t see any benefit of passing the state as parameters, just call the function that change the state without any parameters :

    <script setup>
    const clothingTypes = ['blazerAndShirt', 'blazerAndSweater', 'collarAndSweater', 'graphicShirt'];
    const selectedClothingType = unwrappedRef(clothingTypes[0]);
    
    const nextType = () => {
        const currentIndex = clothingTypes.indexOf(selectedClothingType.value);
        const nextIndex = (currentIndex + 1) % clothingTypes.length;
        selectedClothingType.value = clothingTypes[nextIndex];
    };
    </script>
    
    <template>
      <button @click="nextType">Click me</button>
    </template>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search