inertiajs / inertia

Inertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers.
https://inertiajs.com
MIT License
6.36k stars 428 forks source link

Form helper not preserving state and errors #590

Closed piljac1 closed 1 year ago

piljac1 commented 3 years ago

Hi guys! First of all, this is my first project using the Vue 3/Inertia combo and I gotta say I love it so far! However, I encountered what might not be a bug (could be, but the problem is probably on my side).

So I have this data setup

data() {
  return {
    form: this.$inertia.form({
      redirect_to_page: 'ParentCategorySelection',
      product_option_value_id: '',
      product_color_id: null,
      area: 0,
      option_ids: []
    })
  }
},

So far, everything works alright, all v-models are working and data was validated using Vue devtools, as well as by outputting them directly in the page.

Now comes the time to post the form. Here's what I have:

addProduct(page) {
  this.form.redirect_to_page = page;

  // P.S. this.postRoute comes from a prop
  this.form.post(this.postRoute);
}

When I try to post the form while having invalid fields (according to my form request validation), the page is reloaded because validation errors were encountered (tried removing all validations to see if the reload could be due to something else, but when I do, the behavior is as intended and the user gets redirected on another page as desired).

At this point, this is the intended behavior. The page should be reloaded upon validation errors, like it successfully does right now.

But... the problem is that in the doc (and when I inspect the form object), it mentions that we should be able to access errors from the form using form.error.the_field. However, the error object is always empty, despite the fact that the global $form.props.errors contain the appropriate errors.

Also, reading the doc, the state should be preserved automatically when using the post method. It is not the case for me. All form attributes fall back to their default values. I tried explicitly setting the preserveState flag to true, but no dice.

Let me know if you need more info. Thanks in advance for your input!

EDIT :

My present workaround is to retrieve all inputs in my controller create method and send them as an oldForm prop. Then, in my Vue component, I do the following:

form: this.$inertia.form(
  _.isEmpty(this.oldForm)
    ? {
      redirect_to_page: 'ParentCategorySelection',
      product_option_value_id: '',
      product_flodeco_color_id: null,
      area: 0,
      option_ids: []
    }
    : this.oldForm
),

This isn't ideal because I still don't know why the form helper doesn't send back errors and doesn't preserve the state, but it fixes my issue for now because I need to meet the deadline.

However, I'd like to understand why it doesn't work so I can hopefully fix it before the release. I'm baffled right now because I look at the PingCRM demo and the default Breeze scaffolding and what I did is pretty much the same apport separating my validation in a form request (I had also tried to put the validation in the controller like in the doc and the PingCRM demo, but it didn't fix the issue). I also use the LaravelLocalization package, but it doesn't seem to do unwanted redirections. I tried to disable it anyway to debug, but it didn't help.

piljac1 commented 3 years ago

Still haven't understood/found why it doesn't work, any help would be appreciated. Thanks in advance :)

charliepage88 commented 3 years ago

Having the same issue without the Form Helper, but it could be the same issue. Have post data sent out like so:

this.$inertia.post('url', { data here})

With validation I was testing that data would correctly be set back, but instead the value when first loading the page is set. So if the "name" field has a value of "abcdef" and I delete it and have a validation error on another field come back, the value of "name" is set back to "abcdef" instead of the value of empty or null.

JohnCarlo29 commented 3 years ago

I encountered this issue also. On a page I have 2 components that has this.$inertia.form() inside. One of my forms got the errors value using form.errors but the other one don't. My workaround on the form that has empty object errors is like this image

leemcd56 commented 3 years ago

I'm encountering the same issue. I'm using the Inertia helper to send form data, such as searches and picking dates. The form helper isn't restoring data post-navigation.

On form submission, this uses a GET request to fetch customers by search string, appending a query string to the URL to allow for pagination. Since the form helper isn't restoring the data, I am having to manually pull the data from the query string and reset the form.

const form = useForm('Customers/Search', {
  search: '',
})

A @change is checking the component this is tied to, and uses a GET request to fetch records. I am having to reset the form the same way as the customer search.

const form = useForm('Appointments/Date', {
  date: new Date(),
})
reinink commented 3 years ago

Hey folks! If you're still having this issue, can you update to the latest version of Inertia and the Vue 3 adapter, and let me know if this is still happening?

leemcd56 commented 3 years ago

Hey folks! If you're still having this issue, can you update to the latest version of Inertia and the Vue 3 adapter, and let me know if this is still happening?

Unfortunately, it's not working for me. 🙁 I am beginning to wonder if I am using it correctly?

Referencing the appointment snippet I posted above, I am changing the date by using this method:

const changeDate = () => {
  Inertia.visit('/appointments', {
    method: 'get',
    data: {
      date: format(form.date, 'yyyy-MM-dd'),
    },
  })
}

Would this lead to the form helper not retaining data?

These are the versions of the Inertia packages:

"@inertiajs/inertia": "^0.9.2",
"@inertiajs/inertia-vue3": "^0.4.4",
"@inertiajs/progress": "^0.2.5",
msonowal commented 3 years ago

in vue3 same for me @reinink After successful submission it is not respecting the new prop data came from the server, The prop changes does show in the Vue dev tools but it is not reflected across the form property hence not rendered in the UI/ input fields. I thinks its kind of internal bug of reactivity rendering.

@leemcd56 Current workaround to successfully update the changes from server side to provide a custom callback in form onSuccess

setup(props) {
    const test = computed(() => props.test)
    const form = useForm({
      name: test.value.name,
      xyz: test.value.branch_name,
    })

const submitForm = () => {
      form.put(route('admin.tests.update', test.value.id), {
        preserveScroll: true,
        onSuccess: () => Object.keys(form.data()).forEach((key) => { form[key] = test.value[key] }),
      })
    }
claudiodekker commented 2 years ago

Hey all,

Trying to understand what's going on here, and I have a couple of questions.

https://github.com/inertiajs/inertia/issues/590#issue-844781337:

[...] it mentions that we should be able to access errors from the form using form.error.the_field. However, the error object is always empty, despite the fact that the global $form.props.errors contain the appropriate errors. [...]

This might sound very silly and maybe it's just a typo in the issue description, but, what happens if you try form.errors instead of form.error?

As far as the 'default values' coming back, that sounds very strange to me. Do you have a reproduceable sample (ideally a git repository where the issue occurs with instructions on how to configure it from scratch and get it to the 'problematic' state), or a screen recording of the behaviour?

I almost can't imagine how this would happen, as Inertia's requests are AJAX, the only case that the form would reset is if the page reloads, which only happens when:

Under no circumstances should Inertia change your form's filled input, unless you tell it to do so or state is lost by manually navigating away.

Thanks!

flexchar commented 1 year ago

I've encountered the same of form.errors always being empty even though I can see them being flashed in the response from Laravel. I'll try to recreate a minimal repo.

reinink commented 1 year ago

Hey! Thanks so much for your interest in Inertia.js and for sharing this issue/suggestion.

In an attempt to get on top of the issues and pull requests on this project I am going through all the older issues and PRs and closing them, as there's a decent chance that they have since been resolved or are simply not relevant any longer. My hope is that with a "clean slate" me and the other project maintainers will be able to better keep on top of issues and PRs moving forward.

Of course there's a chance that this issue is still relevant, and if that's the case feel free to simply submit a new issue. The only thing I ask is that you please include a super minimal reproduction of the issue as a Git repo. This makes it much easier for us to reproduce things on our end and ultimately fix it.

Really not trying to be dismissive here, I just need to find a way to get this project back into a state that I am able to maintain it. Hope that makes sense! ❤️