Mini-ghost / vorms

Vue Form Validation with Composition API
https://vorms.mini-ghost.dev
MIT License
521 stars 18 forks source link

Can the `initialValue` of `useForm` be populated with a ref? #23

Open johnson86tw opened 1 year ago

johnson86tw commented 1 year ago

Describe the feature

Greetings,

I am currently implementing a scenario using this package. In the case of searching for a product by name, I would like to have my reactive URL, reactive form, and reactive API request all share the same ref. The code structure would look something like this:

// Updates the URL synchronously
const { search } = useRouteQuery("search") 

// Validates the input
const { values } = useForm({ 
    initialValues: {
        search: search,
    }
}

// Allows reusability of this composable in other components
const { products, pending, error, refresh } = await useProducts({ 
    params: {
        search: search
    }
})

When designing the useProducts function, I modified the type of useProductsOption.params.search to type MaybeRef<T> = T | Ref<T>, allowing it to accept a ref and share the same set of ref variables. I would like to inquire whether the initialValues of useForm can achieve this functionality.

Perhaps there is a better way to solve my issue of sharing the same ref? I would like to hear your suggestions.

Cheers

Additional information

Mini-ghost commented 1 year ago

Thank you very much for sharing your thoughts.

Indeed, the initial version of Vorms didn't consider passing a Reactive or Ref directly. I just tried a simple test, and it seems to have the potential to work. However, I believe I need some time to check if there might be any side effects, so it may not be an immediate solution.

Here's the current idea:

// This is a `Reactive` or `Ref`
const searchParams = useRouteQuery()

const { values, dirty } = useForm({
  initialValues: searchParams
})

If searchParams is a Reactive, then values would be equal to searchParams, and dirty would be based on the initial values at the time of initialization.

However, if possible, I would also appreciate having more use cases for this solution, as it would be great to apply it to different scenarios.

Additionally, based on the scenario you provided, perhaps directly binding the search value to the form control instead of using Vorms could solve this issue?

johnson86tw commented 1 year ago

So, if I understand correctly, you're suggesting that I can skip using the useForm composable and directly bind the "search" with the input field. However, in case I want to perform validation on the "search" input, I'm unsure if it fits the use case of Vorms in this context, where it's not about submitting a form but rather implementing a search and filtering functionality. What is your opinion on the matter?

Mini-ghost commented 1 year ago

Yes, based on the scenario you provided, using Vorms may not make your problem simpler.

Especially in your example:

const { values } = useForm({ 
    initialValues: {
        // search is a `Ref`
        search: search,
    }
}

If search is a Ref and it is only used as a property of initialValues rather than initialValues itself, I think I would need to check each property individually during initialization, which might make the situation more complicated, and there may be issues with resetForm as it currently stands.

If search is a Reactive or Ref and the root is an object, there is a greater possibility that it will work in the idea I proposed, but I still need to write some test cases to verify.

Additionally, if you want to perform validation while typing, you can use it like this:

const { register } = useForm({
  initialValues: searchParams,
  validateMode: 'change', // or 'input'
})

// need to bind value and attributes on the input field
const { value, attrs } = register('keyword')

However, it still requires waiting for Vorms to support passing a Reactive or Ref as initialValues in order to solve your problem.

I apologize if I didn't directly solve your problem, but I appreciate the suggestions you provided as they gave me some interesting ideas.

johnson86tw commented 1 year ago

Regarding the idea you presented, I believe I may require a more flexible design to separately define the reactive route query and useForm's initialValues. For instance, when it comes to the "page" parameter, I do not need to validate it, so the structure of routeQuery might differ from that of initialValues:

// This is a `Reactive`
const routeQuery = useRouteQuery({
        search: route.query.search,
        page: route.query.page,
})

const { values } = useForm({
      initialValues: {
              search: toRef(routeQuery, "search"),
      }
})

const { products, pending, error, refresh } = await useProducts({
        params: {
              search: toRef(routeQuery, "search"),
              page: toRef(routeQuery, "page"),
        }
})

No worries, I may allocate some time to study this functionality.

When designing the useProducts function, I directly place the argument search: MaybeRef<string> into a new ref. I'm unsure whether this approach is suitable for implementation within Vorms. I referenced the writing style of VueUse, as shown in the following link: https://github.com/vueuse/vueuse/blob/e484c4f8e4320ff58da95c2d18945beb83772b72/packages/core/useTitle/index.ts#LL39C9-L39C14

export function useTitle(
  newTitle: MaybeRef<string | null | undefined> = null,
  ...
) {
...
    const title = ref(newTitle ?? document?.title ?? null)
}
Mini-ghost commented 1 year ago

Thank you for your assistance, and I'm looking forward to the results of your study as well! 💚

Additionally, I might still suggest directly passing routeQuery to Vorms' initialValues. We can skip the validation rules for properties like page or perPage when writing the validation rules. This way, we won't need to create new Ref using toRef.

johnson86tw commented 1 year ago

Indeed, I am also uncertain whether using excessive toRef calls for multiple parameters could potentially lead to performance bottlenecks. However, the advantage of splitting them is that some parameters requiring validation might not come from routeQuery but rather from other variables defined within the page

johnson86tw commented 1 year ago

@Mini-ghost Hi, kindly request your assistance in troubleshooting the problems I encountered while running pnpm build:core. Currently, my objective is to make code alterations and experiment with the new functionalities in the /playground. Would it be necessary to perform a build first in order to observe these changes manifesting in the playground?

截圖 2023-05-28 上午10 02 27

Mini-ghost commented 1 year ago

@chnejohnson Can you please provide the version of Vue you are currently using? You can execute pnpm why vue to confirm.

johnson86tw commented 1 year ago

@Mini-ghost Sure

截圖 2023-05-29 下午7 22 45
Mini-ghost commented 1 year ago

@chnejohnson There doesn't seem to be any issue. I've tried several different environments here and couldn't reproduce the problem. I'm not sure what the reason could be. Have you considered cloning the repository again to give it a try?

johnson86tw commented 1 year ago

Sorry, re-cloning the project solved the problem. Thanks for your help