Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initialization callback to form helper in Vue adapters #1516

Merged
merged 7 commits into from
Apr 14, 2023
Merged

Conversation

reinink
Copy link
Member

@reinink reinink commented Apr 13, 2023

Right now there is no easy way to reinitialize a form using the form helper without providing all the data a second time. This creates unnecessary boilerplate in situations where a simple form.reset() isn't enough because you want to update the values based on props that may have changed. For example:

Before (option 1):

// MyDialog.vue

const props = defineProps({
  company_id: Number,
})

const open = ref(false)
const form = useForm({
  first_name: '',
  last_name: '',
  email: '',
  role: 'User',
  company_id: props.company_id,
})

function open() {
  form.first_name = ''
  form.last_name = ''
  form.email = ''
  form.role = 'User'
  form.company_id = props.company_id
  open.value = true
}

Before (option 2):

// MyDialog.vue

const props = defineProps({
  company_id: Number,
})

const open = ref(false)
const form = useForm(getFormData())

function getFormData() {
   return {
    first_name: '',
    last_name: '',
    email: '',
    role: 'User',
    company_id: props.company_id,
  }
}

function open() {
  Object.assign(form, getFormData())
  open.value = true
}

This PR solves this problem by adding an new optional initialization callback to the form helper. This function is automatically called when resetting the form, ensuring that the latest component state (props) is used.

// MyDialog.vue

const props = defineProps({
  company_id: Number,
})

const open = ref(false)

const form = useForm(() => ({
  first_name: '',
  last_name: '',
  email: '',
  role: 'User',
  company_id: props.company_id,
}))

function open() {
  form.reset()
  open.value = true
}

@reinink reinink changed the title Add form helper init() method Add initialization callback to form helper Apr 14, 2023
@reinink reinink changed the title Add initialization callback to form helper Add initialization callback to form helper in Vue adapters Apr 14, 2023
@reinink reinink merged commit b369c9a into master Apr 14, 2023
@reinink reinink deleted the form-init branch April 14, 2023 03:23
export default function useForm<TForm>(...args): InertiaForm<TForm> {
const rememberKey = typeof args[0] === 'string' ? args[0] : null
const data = (typeof args[0] === 'string' ? args[1] : args[0]) || {}
const restored = rememberKey ? (router.restore(rememberKey) as { data: any; errors: any }) : null
let defaults = cloneDeep(data)
let defaults = typeof data === 'object' ? cloneDeep(data) : cloneDeep(data())
Copy link
Contributor

@Tofandel Tofandel Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useForm() without any argument now throws an error because it tries to call data which is undefined, but it was a valid call before (in fact it's used widely in laravel)

It should be like this

typeof data === 'function' ? cloneDeep(data()) :  cloneDeep(data)

let cancelToken = null
let recentlySuccessfulTimeoutId = null
let transform = (data) => data

let form = reactive({
...(restored ? restored.data : data),
...(restored ? restored.data : cloneDeep(defaults)),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this is a breaking change: previously, it was possible to pass in a reactive object like this:

const product = reactive({ name: '' });

const form = useForm({ product });

This way, product.name and form.product.name would always be in sync.

However, this no longer works, as data is now deep-cloned twice before spreading into the form object.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@reinink I recently ran into this breaking change while trying to keep a reactive object in sync with the form object. Has there been a proper graceful fix or we may have to find alternative approaches?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants