Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@ export type FormComponentMethods = {
reset: (...fields: string[]) => void
submit: () => void
defaults: () => void
getData: () => Record<string, FormDataConvertible>
getFormData: () => FormData
}

export type FormComponentonSubmitCompleteArguments = Pick<FormComponentMethods, 'reset' | 'defaults'>
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ const Form = forwardRef<FormComponentRef, ComponentProps>(
reset,
submit,
defaults,
getData,
getFormData,
})

useImperativeHandle(ref, exposed, [form, isDirty, submit])
Expand Down
37 changes: 37 additions & 0 deletions packages/react/test-app/Pages/FormComponent/DataMethods.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Form } from '@inertiajs/react'

export default () => {
return (
<div>
<h1>Test getData() and getFormData() Methods</h1>

<Form>
{({ getData, getFormData }) => (
<>
<input type="text" name="name" id="name" />

<button
type="button"
onClick={() => {
const data = getData()
console.log('getData result:', data)
}}
>
Test getData()
</button>

<button
type="button"
onClick={() => {
const formData = getFormData()
console.log('getFormData entries:', Object.fromEntries(formData.entries()))
}}
>
Test getFormData()
</button>
</>
)}
</Form>
</div>
)
}
6 changes: 4 additions & 2 deletions packages/svelte/src/components/Form.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@
$: _method = isUrlMethodPair(action) ? action.method : ((method ?? 'get').toLowerCase() as Method)
$: _action = isUrlMethodPair(action) ? action.url : (action as string)

function getFormData(): FormData {
export function getFormData(): FormData {
return new FormData(formElement)
}

// Convert the FormData to an object because we can't compare two FormData
// instances directly (which is needed for isDirty), mergeDataIntoQueryString()
// expects an object, and submitting a FormData instance directly causes problems with nested objects.
function getData(): Record<string, FormDataConvertible> {
export function getData(): Record<string, FormDataConvertible> {
return formDataToObject(getFormData())
}

Expand Down Expand Up @@ -198,5 +198,7 @@
{isDirty}
{submit}
{defaults}
{getData}
{getFormData}
/>
</form>
27 changes: 27 additions & 0 deletions packages/svelte/test-app/Pages/FormComponent/DataMethods.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import type { FormDataConvertible } from '@inertiajs/core'
import { Form } from '@inertiajs/svelte'

function testGetData(getData: () => Record<string, FormDataConvertible>) {
const data = getData()
console.log('getData result:', data)
}

function testGetFormData(getFormData: () => FormData) {
const formData = getFormData()

console.log('getFormData entries:', Object.fromEntries(formData.entries()))
}
</script>

<div>
<h1>Test getData() and getFormData() Methods</h1>

<Form let:getData let:getFormData>
<input type="text" id="name" name="name" />

<button type="button" on:click={() => testGetData(getData)}> Test getData() </button>

<button type="button" on:click={() => testGetFormData(getFormData)}> Test getFormData() </button>
</Form>
</div>
1 change: 1 addition & 0 deletions packages/svelte/test-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"sourceMap": true,
"strict": true,
"module": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"baseUrl": ".",
"paths": {
Expand Down
2 changes: 2 additions & 0 deletions packages/vue3/src/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ const Form = defineComponent({
reset,
submit,
defaults,
getData,
getFormData,
}

expose<FormComponentRef>(exposed)
Expand Down
28 changes: 28 additions & 0 deletions packages/vue3/test-app/Pages/FormComponent/DataMethods.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
import { FormDataConvertible } from '@inertiajs/core'
import { Form } from '@inertiajs/vue3'

function testGetData(getData: () => Record<string, FormDataConvertible>) {
const data = getData()
console.log('getData result:', data)
}

function testGetFormData(getFormData: () => FormData) {
const formData = getFormData()
console.log('getFormData entries:', Object.fromEntries(formData.entries()))
}
</script>

<template>
<div>
<h1>Test getData() and getFormData() Methods</h1>

<Form v-slot="{ getData, getFormData }">
<input id="name" type="text" name="name" />

<button type="button" @click="testGetData(getData)">Test getData()</button>

<button type="button" @click="testGetFormData(getFormData)">Test getFormData()</button>
</Form>
</div>
</template>
25 changes: 24 additions & 1 deletion tests/form-component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import test, { expect, Page } from '@playwright/test'
import { pageLoads, requests, scrollElementTo, shouldBeDumpPage } from './support'
import { consoleMessages, pageLoads, requests, scrollElementTo, shouldBeDumpPage } from './support'

test.describe('Form Component', () => {
test.describe('Elements', () => {
Expand Down Expand Up @@ -1448,4 +1448,27 @@ test.describe('Form Component', () => {
expect(dump.form).toEqual({ child: 'A' })
})
})

test.describe('getData and getFormData methods', () => {
test.beforeEach(async ({ page }) => {
consoleMessages.listen(page)
await page.goto('/form-component/data-methods')
})

test('getData returns form data as object', async ({ page }) => {
await page.fill('#name', 'John Doe')
await page.getByRole('button', { name: 'Test getData()' }).click()

const result = consoleMessages.messages.find((msg) => msg.includes('getData result:'))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, consoleMessages was the missing piece. I didn't know about this and that I could listen to console.log() this way.

expect(result).toBe('getData result: {name: John Doe}')
})

test('getFormData returns FormData instance', async ({ page }) => {
await page.fill('#name', 'Jane Doe')
await page.getByRole('button', { name: 'Test getFormData()' }).click()

const formDataMessage = consoleMessages.messages.find((msg) => msg.includes('getFormData entries:'))
expect(formDataMessage).toBe('getFormData entries: {name: Jane Doe}')
})
})
})