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

feat: introduce defineField and deprecate bind API #4497

Merged
merged 14 commits into from
Nov 26, 2023
Merged

Conversation

logaretm
Copy link
Owner

@logaretm logaretm commented Oct 7, 2023

🔎 Overview

This PR removes the following functions on the useForm API:

  • useFieldModel
  • defineInputBinds
  • defineComponentBinds

These methods increased the API surface area and with varying levels of support (useFieldModel being deprecated), it caused some confusion.

Also due to the defineXXXBinds functions combining both the value and props bindings, it causes limitations when dealing with checkboxes and the difference between the two functions may not be apparent at first glance.

So to replace all of those, the defineField is being introduced. It works for both HTML and components due to the separation of the value model and the attributes binding objects and events. This way it could utilize the v-model API without having to worry about the kind of events/prop names to use.

<script setup>
import { useForm } from 'vee-validate';

const { defineField, errors } = useForm({
  validationSchema: schema,
  validateOnMount: true,
});

const { model: email, props: emalProps } = defineField('email', { validateOnModelUpdate: true });
const { model: password, props: pwProps } = defineField('password', { validateOnModelUpdate: true });
</script>

<template>
  <input id="email" name="email" v-model="email" />
  <span id="emailErr">{{ errors.email }}</span>

  <input id="password" name="password" type="password" v-model="password" />
  <span id="passwordErr">{{ errors.password }}</span>
</div>
</template>

I have not decided yet if this is a breaking change to introduce in v5 or if we could do a v4.12 with support for all of these APIs with deprecation notices.

closes #4530
closes #4493
closes #4547

@codecov
Copy link

codecov bot commented Oct 7, 2023

Codecov Report

Attention: 41 lines in your changes are missing coverage. Please review.

Comparison is base (43561e2) 97.01% compared to head (85edc60) 96.12%.

Files Patch % Lines
packages/vee-validate/src/useForm.ts 62.38% 41 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4497      +/-   ##
==========================================
- Coverage   97.01%   96.12%   -0.89%     
==========================================
  Files          86       86              
  Lines        7091     7140      +49     
  Branches     1342     1333       -9     
==========================================
- Hits         6879     6863      -16     
- Misses        212      277      +65     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@timmaier
Copy link

timmaier commented Nov 7, 2023

Hey in relation to original discussion https://github.com/logaretm/vee-validate/discussions/4501|

That opened enhancement issue #4508

I just wanted to add some reproductions on my use case:

With vee-validate version 4.11.8 and defineComponentBinds
https://stackblitz.com/edit/github-gdgttl-7ndkvg?file=src%2Fcomponents%2FSelector.vue

With vee-validate version 4..12.0-alpha.1 using new defineField instead and binding model to the v-model of headless ui radio
https://stackblitz.com/edit/github-gdgttl-yda6dq?file=src%2Fcomponents%2FSelector.vue

In this stack blitz I was expecting the model value exposed by defineField to work with the RadioGroups v-model.

So perhaps it would be nice to expose a binds: on the defineField as you suggested in #4508 that acts as the aggregated version again?

@logaretm
Copy link
Owner Author

logaretm commented Nov 24, 2023

@timmaier I didn't see your comment, sorry.

This API decouples the value from the binds object to solve a few issues:

  • A lot of 3rd party component libraries have a wrapping Field wrapper around their input controls which usually receive the misc props like errors and what not so you end up binding it to both the control and the wrapping component which causes a few bugs with notable examples being Vuetify and AntDesign.
  • v-bind is more prone to type errors if your component doesn't emit the correct value types for that field, v-model is a bit more relaxed in its typing errors when used in the template.
  • You can modify the value without hacking the binding object apart.
  • One unified API for any kind of input/component
  • Works well with Radios and Checkboxes.

For your example, the defineField actually returns an array instead of an object. This is because the DX of array destructuring is much easier for stuff that are meant to be renamed all the time. The description is outdated, sorry about that.

const [selectedPickupDateType] = props.form.defineField('data.type');

I tested that in your example and it works well. Let me know if you have other notes or questions.

@logaretm logaretm merged commit f9a9584 into main Nov 26, 2023
5 of 7 checks passed
@logaretm logaretm deleted the feat/better-binds-api branch November 26, 2023 16:11
@timmaier
Copy link

Sorry to comment on a merged PR.

Thankyou for the the explanation and reasoning regarding v-bind vs v-model and the array syntax all working now :D.

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