vue-formulate icon indicating copy to clipboard operation
vue-formulate copied to clipboard

Scroll user to first form error @submit

Open titusdecali opened this issue 4 years ago • 7 comments

Describe the new feature you'd like

I'd love to see an option to scroll users to the first error input (if an error exists) when they submit a form. Also would like to optionally focus the input that has the error.

Looking at the docs, it looks like this can be done with some kind of custom form error handler, but it would really be appreciated if we could simply set an option like the following:

<FormulateForm
  :scroll-to-error="true"
  :focus-error="true"
>

This was also mentioned in issues #182

If you have a temporary solution to accomplish this, I imagine many others would benefit from it as well.

titusdecali avatar Oct 21 '20 03:10 titusdecali

Sounds like perfect plugin territory to me. Do you have any interest in tackling one yourself?

justin-schroeder avatar Oct 22 '20 17:10 justin-schroeder

@titusdecali Nice feature request.

I also needed this feature in a project I was working on and I was able to accomplish this behavior after checking the hasValidationErrors result from a function triggered by @submit.raw as in the following example.

https://codepen.io/acemir/pen/LYZbozN

This approach has a downside because Element.scrollIntoView with the center option is not widely supported but a polyfill like scroll-into-view or scroll-behavior-polyfill can be used to overcome this limitation.

Either way it would be great to see this as a ready-to-use feature or as a plugin.

acemir avatar Oct 22 '20 23:10 acemir

I was able to accomplish this behavior after checking the hasValidationErrors result from a function triggered by @submit.raw as in the following example.

https://codepen.io/acemir/pen/LYZbozN

You are the man @acemir ! Your solution was perfect for my needs and came right on time to finish a client's project. Can't thank you enough.

I think simply documenting this method is enough for most use cases. @justin-schroeder what do you think about adding it in the docs?

titusdecali avatar Oct 23 '20 00:10 titusdecali

This is right on the edge of what I think the library should do. On one hand, it makes it much easier to use, and we're all about being "the easiest way to build forms with vue". On the other hand, it starts making assumptions about how the form is laid out, and that fields are even on the currently visible screen (as opposed to in a tab) etc. I'm on the fence haha. Someone push me one way or another and I'll go for it.

justin-schroeder avatar Nov 20 '20 21:11 justin-schroeder

While @acemir's solution works perfectly, it's not something directly provided for in the package and thus adding it to the docs might be a bit strange, and I can fully understand that. But, I think this feature is common enough in more complex forms that devs will definitely appreciate having the option of it.

I'd really love to see it on the roadmap.

titusdecali avatar Nov 22 '20 01:11 titusdecali

After more thought I agree this would be a great feature — although I think it falls pretty squarely in "plugin" territory. However, the plugin ecosystem for vue formulate doesn't really exist yet, so I created a new project board called "Plugins" where we can stash good plugin ideas for the community to build out or the maintainers of the project. So we'll keep this open and "kind of" on the road map.

I've been dreaming up lots of ways to kickstart that plugin ecosystem, so more on that to come.

justin-schroeder avatar Nov 23 '20 15:11 justin-schroeder

Thanks @acemir your solution was helpful. For those my want to make it reusable. following is how I am using it as a global method.

<FormulateForm 
      @submit-raw="$global.handleFormulateSubmit($event, submit)" >

// Usage

// Global Method - make sure 2nd Parameter the function you want to call on successful submittion.

const handleFormulateSubmit = (submitResult, submit) => {
  submitResult.hasValidationErrors().then((hasErrors) => {
    if (hasErrors) {
      scrollToError(submitResult.form.$el);
    } else {
      submitResult.values().then((data) => {
        submit();
      });
    }
  });
};

const scrollToError = ($formEl) => {
  const errorWrapperEl = $formEl.querySelector('[data-has-errors="true"]');
  const errorWrapperInput = errorWrapperEl && errorWrapperEl.querySelector("input,select,textarea");
  if (errorWrapperInput) {
    errorWrapperInput.focus();
    errorWrapperInput.scrollIntoView({ block: "center" });
  }
};

Vue.prototype.$global = {
  handleFormulateSubmit,
};

You may also use Mixin or Composable (vue 2.7) but I had hundreds of forms so a global method made more sense.

mudassirmaqbool avatar Dec 05 '23 10:12 mudassirmaqbool