precognition icon indicating copy to clipboard operation
precognition copied to clipboard

Make initial value (third parameter of useForm) dynamic

Open sot1986 opened this issue 1 year ago • 3 comments

Like for the method and url, it would be helpful to have also initial value originated by function.

Example are:

  • initial function is created looking at a computed property values (fetched asynchronously from backend)
  • when you create any object and you use same component for creation or editing (component is not refreshed on success).
  • if you watch any dinamic variable to trigger form reset (typeing search values should reset the query cursor for example).

Thank you.

sot1986 avatar Nov 22 '23 14:11 sot1986

Currently useForm gets method, url and initial value object. Only the method and url are dynamic (string or originated by function). We need also initial object to be dinamic. This because often initial value depends on computed properties, that may vary between form submission.

sot1986 avatar Nov 24 '23 21:11 sot1986

@sot1986 can you please show me a code example demonstrating the issue? I think I get it but I need to see some code to make sure I can address the issue correctly. Thanks!

timacdonald avatar Jan 08 '24 01:01 timacdonald

code in page EditPost.vue used to create new post or edit existing one:

interface Post = {
id: string
title: string
content: string
}

const route = useRoute();

const post: Maybe<Post> = ref(null);

onMounted(async () => {
  if (route.params.postId)
    // fetch post by route params and assign to post value
});

const postForm = useForm(
  () => post.value?.id ? 'PUT' : 'POST',
  () => post.value?.id ? route('post.update', [post.value.id]) : route('post.store'),
  () => {
    title: post.value?.id ?? '',
    content: post.value?.content ?? ''
  }
 )

watch(post, () => {
 postForm.reset()
})

I addressed it on nuxt plugin https://github.com/sot1986/nuxt-laravel-precognition (where is useful to LazyFetch data). Basically I created a specific function (resolveInitialData) in src/utils/core.ts

export function resolveInitialData<T extends Record<string, unknown>>(data: T | (() => T)) {
  return typeof data === 'function'
    ? data()
    : data
}

used in useForm composables.ts

import { resolveInitialData, resolveString } from '../utils/core.ts'

// ...

form = {
    ...cloneDeep(toRaw(resolveInitialData(inputs))),
    data() {
   // ...

   reset(...names) {
      const original = cloneDeep(resolveInitialData(inputs))
      // ...
   }
}

With this approach also in Inertia application you can reuse the same form component (like EditPostForm) without need or creating new one when post id changes, if you use for example Inertia::lazy(fn () => ...).

If you make something different because you think my approach is not ok, please let me know. I will align my repo to your solution. Thanks.

sot1986 avatar Jan 08 '24 08:01 sot1986

I'm going to close this issue, as it is an enhancement instead of a bug.

Feel free to open a PR to support this. We may look at adding the feature in the future.

timacdonald avatar Jun 04 '24 01:06 timacdonald