Component Delay

@aaron-ford
@aaron-ford Adocasts Plus

I made a table for county data. The two columns of importance are the id and name. In my controller in the index function I pass a CountryDto to the page:
countries: CountryDto.fromArray(await Country.all())

In the page, I list it in my props

const props = defineProps<{
    countries: CountryDto[],
}>()
Copied!

And I pass it to an action component, much like was done with the courses index page in PlotMyCourse

:countries="countries"
Copied!

In the template I have a dialog, and in it I have a form input for a dropdown select to pick a country

<FormInput type="select" label="Country" v-model="form.countryId" :error="form.errors.countryId" required>
     <SelectItem v-for="country in props.countries" :key="country.id" :value="Number(country.id)">
          {{ country.name }}
     </SelectItem>
</FormInput>
Copied!

It works, I can use it to select a country, but both opening the dialog, as well as clicking on the country dropdown take 3-5 seconds to load or close. There are a bit over 200 countries in my table, so I don't know if it is a matter of the amount of data it is having to loop through, or if I am doing something wrong. But having a dropdown with that many options doesn't seem unreasonable. Any ideas on how I can speed this up? I tried converting the country data in the controller to an object with the id and name in it, hoping using that rather than a large DTO would speed it up, but that didn't seem to improve the speed.

Thanks.

Create a free account to join in on the discussion
  1. @tomgobich

    Hey Aaron!

    Yeah, I don't think it should have any issue with 200 items. I don't think the select component, for whatever reason, accepts numeric-based values. I set up a quick test mimicking what you have and noticed that the select's performance drops a bit when the devtools are open when using numeric values because it is also logging a warning per SelectItem in the select option set. The max delay I saw on my side using 400 select items was about 1 second, but the severity there could definitely vary per-machine. With the devtools closed everything was fairly snappy.

    Did you have the devtools open when you were having this issue? If so, try closing it and refreshing the page to see if it persists. You could also try it with string-based values to see if that helps.

    0
    1. Responding to tomgobich

      Yeah, that sped it up. I was using numbers since I thought it would need to be a number for the vine validation, but it seems to work. The one thing I can't get the validation to work on when using a string is enums. I read that using v-model.number can force it to be a number, but I haven't been able to get that to work. Maybe because FormInput is a custom component that doesn't support the model modifier? Is there a way to to get a FormInput to transform a string to a number for the backend?

      1
      1. Responding to aaron-ford
        @tomgobich

        Glad to hear that sped things up for ya! There shouldn't be any additional work needed to get v-model.number to work as it is baked into the v-model directive in Vue. However, that approach will likely result in your value never appearing as selected since the form.country value would be cast to a number via v-model.number, but the actual select options would still be strings. Unless they're doing a loose equality check.

        What I would do is utilize Inertia's transform callback to alter the value prior to sending it up to your validation/controller. Below I have a useForm example, but we also show this in our useForm method lesson and the documentation also shows the Form component usage if you're using the latest version of Inertia.

        <script type="ts" setup>
        const form = useForm({
          country: '313',
        })
        
        async function onSubmit() {
          await form
            .transform((data) => ({
              ...data,
              country: Number(data.country)
            }))
            .post('/form-endpoint')
        }
        </script>
        
        <template>
          <form @submit.prevent="onSubmit">
            <!-- ... -->
          </form>
        </template>
        Copied!

        Alternatively, if it fits your use-case, you could look at using a Combobox. The Combobox accepts a value of AcceptableValue which includes a better variety of types. Its similar to a select, but includes search functionalities.

        type AcceptableValue = string | number | bigint | Record<string, any> | null
        Copied!
        0
        1. Responding to tomgobich

          The onSubmmit transform did what I needed, thanks! It's been a while since I've done some of the lessons, so I forgot we'd done that. As always, thanks for the help!

          1
          1. Responding to aaron-ford
            @tomgobich

            Awesome, glad to hear that Aaron! Absolutely, there's plenty of things like that I forget as well and the Inertia docs, from what I could find, doesn't seem to list the useForm transform method anymore in favor of their Form component, so its a little hidden now. Anytime, always happy to help!!

            0
New Discussion
Topic