> ## Documentation Index
> Fetch the complete documentation index at: https://inertiajs-vi.tuantq.online/llms.txt
> Use this file to discover all available pages before exploring further.

# Form

<Warning>Đây là tài liệu Inertia.js v1, phiên bản không còn được duy trì tích cực. Vui lòng tham khảo [tài liệu v3](/v3/getting-started/index).</Warning>

## Submit form

Mặc dù có thể submit form HTML truyền thống với Inertia, cách này không được khuyến nghị vì sẽ làm tải lại toàn bộ trang. Thay vào đó, tốt hơn là chặn việc submit form rồi thực hiện [request bằng Inertia](/v1/the-basics/manual-visits).

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <template>
      <form @submit.prevent="submit">
          <label for="first_name">First name:</label>
          <input id="first_name" v-model="form.first_name" />
          <label for="last_name">Last name:</label>
          <input id="last_name" v-model="form.last_name" />
          <label for="email">Email:</label>
          <input id="email" v-model="form.email" />
          <button type="submit">Submit</button>
      </form>
  </template>

  <script>
  import { router } from '@inertiajs/vue2'

  export default {
      data() {
          return {
              form: {
                  first_name: null,
                  last_name: null,
                  email: null,
              },
          }
      },
      methods: {
          submit() {
              router.post('/users', this.form)
          },
      },
  }
  </script>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <script setup>
  import { reactive } from 'vue'
  import { router } from '@inertiajs/vue3'

  const form = reactive({
      first_name: null,
      last_name: null,
      email: null,
  })

  function submit() {
      router.post('/users', form)
  }
  </script>

  <template>
      <form @submit.prevent="submit">
          <label for="first_name">First name:</label>
          <input id="first_name" v-model="form.first_name" />
          <label for="last_name">Last name:</label>
          <input id="last_name" v-model="form.last_name" />
          <label for="email">Email:</label>
          <input id="email" v-model="form.email" />
          <button type="submit">Submit</button>
      </form>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { useState } from 'react'
  import { router } from '@inertiajs/react'

  export default function Edit() {
      const [values, setValues] = useState({
          first_name: "",
          last_name: "",
          email: "",
      })

      function handleChange(e) {
          const key = e.target.id;
          const value = e.target.value
          setValues(values => ({
                  ...values,
                  [key]: value,
          }))
      }

      function handleSubmit(e) {
          e.preventDefault()
          router.post('/users', values)
      }

      return (
          <form onSubmit={handleSubmit}>
              <label htmlFor="first_name">First name:</label>
              <input id="first_name" value={values.first_name} onChange={handleChange} />
              <label htmlFor="last_name">Last name:</label>
              <input id="last_name" value={values.last_name} onChange={handleChange} />
              <label htmlFor="email">Email:</label>
              <input id="email" value={values.email} onChange={handleChange} />
              <button type="submit">Submit</button>
          </form>
      )
  }
  ```

  ```html Svelte icon="s" theme={null}
  <script>
      import { router } from '@inertiajs/svelte'

      let values = {
          first_name: null,
          last_name: null,
          email: null,
      }

      function handleSubmit() {
          router.post('/users', values)
      }
  </script>

  <form on:submit|preventDefault={handleSubmit}>
      <label for="first_name">First name:</label>
      <input id="first_name" bind:value={values.first_name}>

      <label for="last_name">Last name:</label>
      <input id="last_name" bind:value={values.last_name}>

      <label for="email">Email:</label>
      <input id="email" bind:value={values.email}>

      <button type="submit">Submit</button>
  </form>
  ```
</CodeGroup>

Như bạn có thể đã nhận thấy trong ví dụ trên, khi dùng Inertia, thông thường bạn không cần kiểm tra response của form ở phía client như khi tự thực hiện request XHR / fetch.

Thay vào đó, route / controller phía máy chủ thường trả về một response [redirect](/v1/the-basics/redirects). Và tất nhiên, không có gì ngăn bạn redirect người dùng quay lại đúng trang trước đó. Với cách tiếp cận này, việc xử lý submit form trong Inertia rất giống xử lý submit form HTML truyền thống.

```php theme={null}
class UsersController extends Controller
{
        public function index()
        {
                return Inertia::render('Users/Index', [
                    'users' => User::all(),
                ]);
        }

        public function store(Request $request)
        {
                User::create($request->validate([
                    'first_name' => ['required', 'max:50'],
                    'last_name' => ['required', 'max:50'],
                    'email' => ['required', 'max:50', 'email'],
                ]));

                return to_route('users.index');
        }
}
```

## Validation phía máy chủ

Xử lý lỗi validation phía máy chủ trong Inertia hơi khác so với xử lý lỗi từ request XHR / fetch thủ công. Khi thực hiện request XHR / fetch, bạn thường kiểm tra response có status code `422` rồi tự cập nhật state lỗi của form.

Tuy nhiên, khi dùng Inertia, máy chủ không bao giờ trả response `422`. Thay vào đó, như ví dụ trên, route / controller thường trả về response redirect — tương tự một lần submit form tải toàn bộ trang truyền thống.

Để tìm hiểu đầy đủ về cách xử lý và hiển thị lỗi validation với Inertia, hãy xem tài liệu [validation](/v1/the-basics/validation).

## Form helper

Vì làm việc với form là nhu cầu rất phổ biến, Inertia cung cấp form helper nhằm giảm lượng boilerplate code cần thiết khi xử lý các lần submit form thông thường.

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <template>
      <form @submit.prevent="form.post('/login')">
          <!-- email -->
          <input type="text" v-model="form.email">
          <div v-if="form.errors.email">{{ form.errors.email }}</div>
          <!-- password -->
          <input type="password" v-model="form.password">
          <div v-if="form.errors.password">{{ form.errors.password }}</div>
          <!-- remember me -->
          <input type="checkbox" v-model="form.remember"> Remember Me
          <!-- submit -->
          <button type="submit" :disabled="form.processing">Login</button>
      </form>
  </template>

  <script>
  import { useForm } from '@inertiajs/vue2'

  export default {
      data() {
          return {
              form: useForm({
                  email: null,
                  password: null,
                  remember: false,
              }),
          }
      },
  }
  </script>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <script setup>
  import { useForm } from '@inertiajs/vue3'

  const form = useForm({
      email: null,
      password: null,
      remember: false,
  })
  </script>

  <template>
      <form @submit.prevent="form.post('/login')">
          <!-- email -->
          <input type="text" v-model="form.email">
          <div v-if="form.errors.email">{{ form.errors.email }}</div>
          <!-- password -->
          <input type="password" v-model="form.password">
          <div v-if="form.errors.password">{{ form.errors.password }}</div>
          <!-- remember me -->
          <input type="checkbox" v-model="form.remember"> Remember Me
          <!-- submit -->
          <button type="submit" :disabled="form.processing">Login</button>
      </form>
  </template>
  ```

  ```jsx React icon="react" theme={null}
  import { useForm } from '@inertiajs/react'

  const { data, setData, post, processing, errors } = useForm({
      email: '',
      password: '',
      remember: false,
  })

  function submit(e) {
      e.preventDefault()
      post('/login')
  }

  return (
      <form onSubmit={submit}>
          <input type="text" value={data.email} onChange={e => setData('email', e.target.value)} />
          {errors.email && <div>{errors.email}</div>}
          <input type="password" value={data.password} onChange={e => setData('password', e.target.value)} />
          {errors.password && <div>{errors.password}</div>}
          <input type="checkbox" checked={data.remember} onChange={e => setData('remember', e.target.checked)} /> Remember Me
          <button type="submit" disabled={processing}>Login</button>
      </form>
  )
  ```

  ```html Svelte icon="s" theme={null}
  <script>
  import { useForm } from '@inertiajs/svelte'

  let form = useForm({
      email: null,
      password: null,
      remember: false,
  })

  function submit() {
      $form.post('/login')
  }
  </script>

  <form on:submit|preventDefault={submit}>
      <input type="text" bind:value={$form.email} />
      {#if $form.errors.email}
          <div class="form-error">{$form.errors.email}</div>
      {/if}
      <input type="password" bind:value={$form.password} />
      {#if $form.errors.password}
          <div class="form-error">{$form.errors.password}</div>
      {/if}
      <input type="checkbox" bind:checked={$form.remember} /> Remember Me
      <button type="submit" disabled={$form.processing}>Submit</button>
  </form>
  ```
</CodeGroup>

Để submit form, bạn có thể dùng các phương thức `get`, `post`, `put`, `patch` và `delete`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  form.submit(method, url, options)
  form.get(url, options)
  form.post(url, options)
  form.put(url, options)
  form.patch(url, options)
  form.delete(url, options)
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  form.submit(method, url, options)
  form.get(url, options)
  form.post(url, options)
  form.put(url, options)
  form.patch(url, options)
  form.delete(url, options)
  ```

  ```js React icon="react" theme={null}
  const { submit, get, post, put, patch, delete: destroy } = useForm({ ... })

  submit(method, url, options)
  get(url, options)
  post(url, options)
  put(url, options)
  patch(url, options)
  destroy(url, options)
  ```

  ```js Svelte icon="s" theme={null}
  $form.submit(method, url, options)
  $form.get(url, options)
  $form.post(url, options)
  $form.put(url, options)
  $form.patch(url, options)
  $form.delete(url, options)
  ```
</CodeGroup>

Các phương thức submit hỗ trợ mọi [tùy chọn visit](/v1/the-basics/manual-visits) thông thường như `preserveState`, `preserveScroll` và callback sự kiện; các callback này hữu ích để thực hiện tác vụ sau khi submit form thành công. Ví dụ, bạn có thể dùng callback `onSuccess` để reset input về trạng thái ban đầu.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  form.post('/profile', {
      preserveScroll: true,
      onSuccess: () => form.reset('password'),
  })
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  form.post('/profile', {
      preserveScroll: true,
      onSuccess: () => form.reset('password'),
  })
  ```

  ```js React icon="react" theme={null}
  const { post, reset } = useForm({ ... })

  post('/profile', {
      preserveScroll: true,
      onSuccess: () => reset('password'),
  })
  ```

  ```js Svelte icon="s" theme={null}
  $form.post('/profile', {
      preserveScroll: true,
      onSuccess: () => $form.reset('password'),
  })
  ```
</CodeGroup>

Nếu cần thay đổi dữ liệu form trước khi gửi đến máy chủ, bạn có thể thực hiện thông qua phương thức `transform()`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  form
      .transform((data) => ({
          ...data,
          remember: data.remember ? 'on' : '',
      }))
      .post('/login')
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  form
      .transform((data) => ({
          ...data,
          remember: data.remember ? 'on' : '',
      }))
      .post('/login')
  ```

  ```js React icon="react" theme={null}
  const { transform } = useForm({ ... })

  transform((data) => ({
      ...data,
      remember: data.remember ? 'on' : '',
  }))
  ```

  ```js Svelte icon="s" theme={null}
  $form
      .transform((data) => ({
          ...data,
          remember: data.remember ? 'on' : '',
      }))
      .post('/login')
  ```
</CodeGroup>

Bạn có thể dùng thuộc tính `processing` để theo dõi form có đang được submit hay không. Điều này hữu ích để ngăn submit hai lần bằng cách disable nút submit.

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <button type="submit" :disabled="form.processing">Submit</button>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <button type="submit" :disabled="form.processing">Submit</button>
  ```

  ```jsx React icon="react" theme={null}
  const { processing } = useForm({ ... })

  <button type="submit" disabled={processing}>Submit</button>
  ```

  ```svelte Svelte icon="s" theme={null}
  <button type="submit" disabled={$form.processing}>Submit</button>
  ```
</CodeGroup>

Nếu form đang tải file lên, sự kiện tiến trình hiện tại có sẵn thông qua thuộc tính `progress`, giúp bạn dễ dàng hiển thị tiến độ tải lên.

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <progress v-if="form.progress" :value="form.progress.percentage" max="100">
      {{ form.progress.percentage }}%
  </progress>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <progress v-if="form.progress" :value="form.progress.percentage" max="100">
      {{ form.progress.percentage }}%
  </progress>
  ```

  ```jsx React icon="react" theme={null}
  const { progress } = useForm({ ... })

  {progress && (
      <progress value={progress.percentage} max="100">
          {progress.percentage}%
      </progress>
  )}
  ```

  ```svelte Svelte icon="s" theme={null}
  {#if $form.progress}
      <progress value={$form.progress.percentage} max="100">
          {$form.progress.percentage}%
      </progress>
  {/if}
  ```
</CodeGroup>

Nếu có lỗi validation của form, chúng có sẵn thông qua thuộc tính `errors`. Khi xây dựng ứng dụng Inertia dùng Laravel, lỗi form sẽ tự động được điền khi ứng dụng ném ra instance `ValidationException`, chẳng hạn khi dùng `{'$request->validate()'}`.

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <div v-if="form.errors.email">{{ form.errors.email }}</div>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <div v-if="form.errors.email">{{ form.errors.email }}</div>
  ```

  ```jsx React icon="react" theme={null}
  const { errors } = useForm({ ... })

  {errors.email && <div>{errors.email}</div>}
  ```

  ```svelte Svelte icon="s" theme={null}
  {#if $form.errors.email}
      <div>{$form.errors.email}</div>
  {/if}
  ```
</CodeGroup>

Để tìm hiểu kỹ hơn về validation và lỗi của form, hãy xem [tài liệu validation](/v1/the-basics/validation).

Để xác định form có lỗi hay không, bạn có thể dùng thuộc tính `hasErrors`. Để xóa lỗi form, dùng phương thức `clearErrors()`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  // Clear all errors...
  form.clearErrors()

  // Clear errors for specific fields...
  form.clearErrors('field', 'anotherfield')
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  // Clear all errors...
  form.clearErrors()

  // Clear errors for specific fields...
  form.clearErrors('field', 'anotherfield')
  ```

  ```js React icon="react" theme={null}
  const { clearErrors } = useForm({ ... })

  // Clear all errors...
  clearErrors()

  // Clear errors for specific fields...
  clearErrors('field', 'anotherfield')
  ```

  ```js Svelte icon="s" theme={null}
  // Clear all errors...
  $form.clearErrors()

  // Clear errors for specific fields...
  $form.clearErrors('field', 'anotherfield')
  ```
</CodeGroup>

Nếu sử dụng thư viện validation input phía client hoặc tự validation phía client, bạn có thể tự đặt lỗi cho form bằng phương thức `setErrors()`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  // Set a single error...
  form.setError('field', 'Your error message.');

  // Set multiple errors at once...
  form.setError({
      foo: 'Your error message for the foo field.',
      bar: 'Some other error for the bar field.'
  });
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  // Set a single error...
  form.setError('field', 'Your error message.');

  // Set multiple errors at once...
  form.setError({
      foo: 'Your error message for the foo field.',
      bar: 'Some other error for the bar field.'
  });
  ```

  ```js React icon="react" theme={null}
  const { setError } = useForm({ ... })

  // Set a single error...
  setError('field', 'Your error message.');

  // Set multiple errors at once...
  setError({
      foo: 'Your error message for the foo field.',
      bar: 'Some other error for the bar field.'
  });
  ```

  ```js Svelte icon="s" theme={null}
  // Set a single error
  $form.setError('field', 'Your error message.');

  // Set multiple errors at once
  $form.setError({
      foo: 'Your error message for the foo field.',
      bar: 'Some other error for the bar field.'
  });
  ```
</CodeGroup>

Khác với một lần submit form thực tế, props của trang không thay đổi khi bạn tự đặt lỗi trên một instance form.

Khi form được submit thành công, thuộc tính `wasSuccessful` sẽ là `true`. Ngoài ra, form còn có thuộc tính `recentlySuccessful`, được đặt thành `true` trong hai giây sau một lần submit thành công. Bạn có thể dùng thuộc tính này để hiển thị thông báo thành công tạm thời.

Để reset các giá trị của form về giá trị mặc định, bạn có thể dùng phương thức `reset()`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  // Reset the form...
  form.reset()

  // Reset specific fields...
  form.reset('field', 'anotherfield')
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  // Reset the form...
  form.reset()

  // Reset specific fields...
  form.reset('field', 'anotherfield')
  ```

  ```js React icon="react" theme={null}
  const { reset } = useForm({ ... })

  // Reset the form...
  reset()

  // Reset specific fields...
  reset('field', 'anotherfield')
  ```

  ```js Svelte icon="s" theme={null}
  // Reset the form...
  $form.reset()

  // Reset specific fields...
  $form.reset('field', 'anotherfield')
  ```
</CodeGroup>

Nếu các giá trị mặc định của form không còn phù hợp, bạn có thể dùng phương thức `defaults()` để cập nhật chúng. Sau đó, form sẽ được reset về đúng các giá trị này trong lần tiếp theo phương thức `reset()` được gọi.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  // Set the form's current values as the new defaults...
  form.defaults()

  // Update the default value of a single field...
  form.defaults('email', 'updated-default@example.com')

  // Update the default value of multiple fields...
  form.defaults({
      name: 'Updated Example',
      email: 'updated-default@example.com',
  })
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  // Set the form's current values as the new defaults...
  form.defaults()

  // Update the default value of a single field...
  form.defaults('email', 'updated-default@example.com')

  // Update the default value of multiple fields...
  form.defaults({
      name: 'Updated Example',
      email: 'updated-default@example.com',
  })
  ```

  ```js React icon="react" theme={null}
  const { setDefaults } = useForm({ ... })

  // Set the form's current values as the new defaults...
  setDefaults()

  // Update the default value of a single field...
  setDefaults('email', 'updated-default@example.com')

  // Update the default value of multiple fields...
  setDefaults({
      name: 'Updated Example',
      email: 'updated-default@example.com',
  })
  ```

  ```js Svelte icon="s" theme={null}
  // Set the form's current values as the new defaults...
  $form.defaults()

  // Update the default value of a single field...
  $form.defaults('email', 'updated-default@example.com')

  // Change the default value of multiple fields...
  $form.defaults({
      name: 'Updated Example',
      email: 'updated-default@example.com',
  })
  ```
</CodeGroup>

Để xác định form có thay đổi nào hay không, bạn có thể dùng thuộc tính `isDirty`.

<CodeGroup>
  ```vue Vue 2 icon="vuejs" theme={null}
  <div v-if="form.isDirty">There are unsaved form changes.</div>
  ```

  ```vue Vue 3 icon="vuejs" theme={null}
  <div v-if="form.isDirty">There are unsaved form changes.</div>
  ```

  ```jsx React icon="react" theme={null}
  const { isDirty } = useForm({ ... })

  {isDirty && <div>There are unsaved form changes.</div>}
  ```

  ```html Svelte icon="s" theme={null}
  {#if $form.isDirty}
      <div>There are unsaved form changes.</div>
  {/if}
  ```
</CodeGroup>

Để hủy một lần submit form, dùng phương thức `cancel()`.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  form.cancel()
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  form.cancel()
  ```

  ```js React icon="react" theme={null}
  const { cancel } = useForm({ ... })

  cancel()
  ```

  ```js Svelte icon="s" theme={null}
  $form.cancel()
  ```
</CodeGroup>

Để yêu cầu Inertia lưu dữ liệu và lỗi của form vào [history state](/v1/advanced/remembering-state), bạn có thể truyền một form key duy nhất làm đối số đầu tiên khi khởi tạo form.

<CodeGroup>
  ```js Vue 2 icon="vuejs" theme={null}
  import { useForm } from '@inertiajs/vue2'

  form: useForm('CreateUser', data)
  form: useForm(`EditUser:${this.user.id}\
  ```

  ```js Vue 3 icon="vuejs" theme={null}
  import { useForm } from '@inertiajs/vue3'

  const form = useForm('CreateUser', data)
  const form = useForm(`EditUser:${user.id}\
  ```

  ```js React icon="react" theme={null}
  import { useForm } from '@inertiajs/react'

  const form = useForm('CreateUser', data)
  const form = useForm(`EditUser:${user.id}\
  ```

  ```js Svelte icon="s" theme={null}
  import { useForm } from '@inertiajs/svelte'

  const form = useForm('CreateUser', data)
  const form = useForm(`EditUser:${user.id}\
  ```
</CodeGroup>

## Tải file lên

Khi thực hiện request hoặc submit form có chứa file, Inertia sẽ tự động chuyển dữ liệu request thành object `FormData`.

Để tìm hiểu kỹ hơn về tải file, hãy xem [tài liệu tải file](/v1/the-basics/file-uploads).

## Submit bằng XHR / Fetch

Dùng Inertia để submit form phù hợp với phần lớn tình huống; tuy nhiên, nếu cần kiểm soát quá trình submit chi tiết hơn, bạn hoàn toàn có thể thực hiện request XHR hoặc `fetch` thuần bằng thư viện mình lựa chọn.

***

## Tài liệu chính thức

Bài dịch này được đối chiếu từ [tài liệu Inertia.js v1 chính thức](https://inertiajs.com/docs/v1/the-basics/forms). Nếu có khác biệt do phiên bản hoặc cập nhật mới, hãy ưu tiên tài liệu chính thức làm nguồn tham chiếu.
