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

Incorrect behavior of the reatomField form's method #1056

Open
temapavloff opened this issue Feb 25, 2025 · 0 comments
Open

Incorrect behavior of the reatomField form's method #1056

temapavloff opened this issue Feb 25, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@temapavloff
Copy link

What happened?

A field create by Form.reatomField method isn't affected by the validation during the Form.onSubmit call

I took the example from the documentation and written a unit test for it:

// The example from the doc (https://www.reatom.dev/package/form/)
import { reatomForm } from '@reatom/form'

export const loginForm = reatomForm(
  {
    async onSubmit(ctx) {
      const user = await api.login(ctx, {
        name: ctx.get(nameField),
        password: ctx.get(passwordField),
      })
    },
  },
  'loginForm',
)
export const nameField = loginForm.reatomField({ initState: '' }, 'nameField')
export const passwordField = loginForm.reatomField(
  {
    initState: '',
    validate(ctx, { state }) {
      if (state.length < 6)
        throw new Error('The password should have at least six characters.')
    },
  },
  'passwordField',
)

// My unit tests
import test from 'node:test';
import assert from 'node:assert';

import { loginForm, passwordField } from '../src/index.js';
import { createCtx } from '@reatom/framework';

test('Login form', () => {
  const ctx = createCtx();

  loginForm.onSubmit(ctx);

  assert.strictEqual(
    ctx.get(passwordField.validationAtom).error,
    'The password should have at least six characters.',
  );
});

The test fails. I've figured out the the password field's validate isn't called at all during the submit.
It happens because the internal validation function expects that the field is in the fieldsListAtom,
but a field gets into it only on the first change. The implementation:

// https://github.com/artalar/reatom/blob/v3/packages/form/src/reatomForm.ts#L146
const reatomFormField: Form['reatomField'] = (
    options,
    fieldName = options.name ?? __count(`${typeof options.initState}Field`),
  ) => {
    // ...
   
    atomField.onChange((ctx) => {
      if (isInit(ctx)) {
        fieldsListAtom(ctx, (list) => [...list, atomField])
      }
    })
    
    // ...
  }

I expect that field's validation callback is called even if the field was not changed since the initialization, because it should be possible to see validation messages even if the form was submitted without change fields values.

Field.remove function adds another copy of the field to fieldsListAtom

The implementation:

// https://github.com/artalar/reatom/blob/v3/packages/form/src/reatomForm.ts#L146
const reatomFormField: Form['reatomField'] = (
    options,
    fieldName = options.name ?? __count(`${typeof options.initState}Field`),
  ) => {
    // ...
    atomField.remove = action((ctx) => {
      fieldsListAtom(ctx, (list) => [...list, atomField]) // <- it should filter out the atomField
    }, `${fieldName}.remove`)

    // ...
  }

Part

Package @reatom/form

Version

3.3.2

What browsers are you seeing the problem on?

No response

Relevant log output

@temapavloff temapavloff added the bug Something isn't working label Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant