ant-design / ant-design

An enterprise-class UI design language and React UI library
https://ant.design
MIT License
90.7k stars 46.99k forks source link

form.setFieldsValue not fires onFieldsChange or onValuesChange #23782

Closed Ragnaxander closed 4 years ago

Ragnaxander commented 4 years ago

Reproduction link

Edit on CodeSandbox

Steps to reproduce

use form.setFieldsValue for setting new form values.

What is expected?

form.setFieldsValue also fires onFieldsChange or onValuesChange.

What is actually happening?

form.setFieldsValue not fires onFieldsChange or onValuesChange.

Environment Info
antd 4.2.0
React react latest
System windows 10
Browser chrome latest
yoyo837 commented 4 years ago

https://github.com/react-component/field-form#-setfields-not-trigger-onfieldschange-and-setfieldsvalue-not-trigger-onvalueschange

Ragnaxander commented 4 years ago

i got it

dukeliberal commented 3 years ago

https://github.com/react-component/field-form#-setfields-not-trigger-onfieldschange-and-setfieldsvalue-not-trigger-onvalueschange

@yoyo837 , What's means about this link? how did it work for this issue?

anikkon commented 3 years ago

Hey @dukeliberal

Looks like ant-design documentation now includes a chapter on this: https://ant.design/components/form/#setFieldsValue-do-not-trigger-onFieldsChange-or-onValuesChange :

Here's what it says:

> setFieldsValue do not trigger onFieldsChange or onValuesChange?
It's by design. Only user interactive can trigger the change event. This design is aim to avoid call setFieldsValue in change event which may makes loop calling.
dukeliberal commented 2 years ago

Hey @dukeliberal

Looks like ant-design documentation now includes a chapter on this: https://ant.design/components/form/#setFieldsValue-do-not-trigger-onFieldsChange-or-onValuesChange :

Here's what it says:

> setFieldsValue do not trigger onFieldsChange or onValuesChange?
It's by design. Only user interactive can trigger the change event. This design is aim to avoid call setFieldsValue in change event which may makes loop calling.

Thank u, guy.

lopesrichard commented 2 years ago

Hey @dukeliberal

Looks like ant-design documentation now includes a chapter on this: https://ant.design/components/form/#setFieldsValue-do-not-trigger-onFieldsChange-or-onValuesChange :

Here's what it says:

> setFieldsValue do not trigger onFieldsChange or onValuesChange?
It's by design. Only user interactive can trigger the change event. This design is aim to avoid call setFieldsValue in change event which may makes loop calling.

This decision doesn't make sense to me. I usually have to make dumb setStates to update the UI because setFields do nothing.

bsayat commented 1 year ago

i think that this method have to has options property, like setFieldsValue(values, { triggerFieldsChange: boolean, triggerValuesChange: boolean }). that will trigger onFieldsChange or onValuesChange if their values are true.

alveshelio commented 1 year ago

I'm done with AntD Form, this is by far the worst form you can work with. I'm switching to react-hook-form. The API sucks, validating a form is a pain and all this is a waste for time :(

SleepWalker commented 1 year ago

You can also use the following hack as a replacement for onFieldsChange:

<Form.Item shouldUpdate>
  {((isParentRender) => () => {
    // using this instead of Form.onValuesChange prop
    // because the last one will not be triggered on form.setFieldValue()

    if (isParentRender) {
      // do not execute any logic on parent component render to avoid render loops
      isParentRender = false;

      return;
    }

    // use timeout because this callback is executed in rendering
    // context where setState is not expected
    setTimeout(() => {
      const values = form.getFieldsValue();

      const result = doSomeStaff(values);

      setSomeState(result);
    });

    return null;
  })(true)}
</Form.Item>

Not that pretty, but should work as expected :sweat_smile:

yuki2006 commented 1 year ago

I believe it would be beneficial to create a new API separate from 'onFieldsChange' and 'onValuesChange'. This new API could accommodate recursive calls, leaving the responsibility of handling these calls to the user. This would provide more flexibility without altering the behavior of existing APIs. Please consider this suggestion for future updates. Thank you.

techoutlooks commented 7 months ago

One way is to 'fool' onValuesChange() by simulating real interaction, calling the native API directly; ie. call native setter and 'change' event dispatch like so:

export function setInputField ({id, value}) {

  // set input value
  var input = document.getElementById(id);
  var nativeInputValueSetter = Object.getOwnPropertyDescriptor(
    window.HTMLInputElement.prototype, "value").set;
  nativeInputValueSetter.call(input, value);

  // dispatch change event
  var inputEvent = new Event("change", { bubbles: true });
  input.dispatchEvent(inputEvent);
}

Thread: https://stackoverflow.com/a/46012210

gerald24 commented 3 weeks ago

Another solution might be using the internal hooks api. It's not clean, but unfortunately not all interfaces are given to the outside world.

export function updateFieldValue<Values = any>(form: FormInstance<Values>, name: string, value: any) {
  (form as any).getInternalHooks('RC_FORM_INTERNAL_HOOKS').dispatch({
    type: 'updateValue',
    namePath: [name],
    value: value
  })
}

This will trigger onValuesChange and onFieldsChange, but latter with touched: false

I also use the internal hooks api for change the initial values during the runtime (needed for ui updates/multiuser changes)

export function setFormInitialValues<Values = any>(form: FormInstance<Values>, initialValues: Values | null) {
  (form as any).getInternalHooks('RC_FORM_INTERNAL_HOOKS').setInitialValues(initialValues, true)
}