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

Data in primeInputNumber not updating on input #53

Closed
ArnarArnar opened this issue Sep 20, 2024 · 9 comments
Closed

Data in primeInputNumber not updating on input #53

ArnarArnar opened this issue Sep 20, 2024 · 9 comments

Comments

@ArnarArnar
Copy link

The InputNumber component from the FormKit-PrimeVue integration does not update the data properly when input is modified. Although the formatted value is displayed correctly, the reactive data model does not reflect changes, leaving the value unchanged after input events.

Steps to Reproduce:

  1. Go to the demo page: https://formkit-primevue.netlify.app/inputs/inputNumber
  2. Modify the InputNumber value in the form.
  3. Observe that the data model does not update as expected.

Expected Behavior:

The data model should be updated in real-time when the user inputs a value.

Actual Behavior:

While the number is formatted and displayed correctly, the reactive model is not updated, and the original value remains unchanged.

Possible Cause:

In the current implementation, the handleInput function uses context?._value, which does not correctly reflect the new input value. Changing this line in useFormKitInput to use _.value seems to resolve the issue:

function handleInput(_: any) {
    // context?.node.input(context?._value) // This is the original line
    context?.node.input(_.value) // This is the modified line
}

Additional Context:

I might be missing something here, as there could be a reason why context?._value is used instead of the direct value. It works fine in other components but not with InputNumber, so the issue might be more complex.

Just wanted to point this out and congratulate you on this fantastic repository!

@sfxcode
Copy link
Owner

sfxcode commented Sep 20, 2024

Hi,

you are right. In case of input number changes was not reflected and your proposal fixed it.
In other cases it works as expected.

Thank you for reporting this issue and your nice words about this framework, i try my best to keep it in sync with every changes in PrimeVue.

Have a nice coding time and greetings,

Tom

@ArnarArnar
Copy link
Author

Hi, it's Arnar again!

I really appreciate the work done so far, but after further testing, I realized that my initial fix for updating context._value wasn’t fully sufficient, particularly when a min value is set. Specifically:

Issue:

  • When a min value (e.g., 10) is set, inputting a lower value like "9" will correctly update the displayed value, but the context does not reflect this change and continues to use the old value (e.g., 9 instead of 10).
  • Additionally, I encountered a problem with floating-point precision. Even though minFractionDigits and maxFractionDigits were set correctly, there were cases where the value still carried extra decimal places.
    Solution:

The issue with handling the min value can be solved by explicitly syncing the localValue with the context on input.
For the floating-point precision issue, I implemented a rounding function to handle floating-point imprecision.

Example Fix:

// Component - PrimeInputNumber (revised)

// Rounding function to fix floating-point precision issues
function roundToDecimals(value: any, decimals: number) {
  const factor = Math.pow(10, decimals)
  return Math.round(value * factor) / factor
}

// Create a local ref for the value, initialized with context._value
const localValue = ref(props.context._value)

// Watch the prop value for changes from the parent, and update the local value if necessary
watch(
  () => props.context._value,
  (newValue) => {
    if (newValue !== localValue.value) {
      localValue.value = newValue
    }
  }
)

// Watch localValue, but only update context.node.input if necessary
watch(localValue, (newValue) => {
  const roundedValue = roundToDecimals(newValue, props.context.maxFractionDigits ?? 2)
  if (roundedValue !== props.context._value) {
    props.context.node.input(roundedValue)
  }
})

// Handle input event and emit rounded value
function handleInputNumber(e: InputNumberInputEvent) {
  const roundedValue = roundToDecimals(e.value, props.context.maxFractionDigits ?? 2)
  if (roundedValue !== localValue.value) {
    localValue.value = roundedValue
  }
}

Explanation:

  • The localValue is kept in sync with context._value, but we avoid redundant updates by only emitting changes when the values differ after rounding.
  • A roundToDecimals helper function is used to ensure that the value is correctly rounded both when the input changes and when it is blurred.

I've attached a simple schema to demonstrate how these changes now work, I wanted to test it toughly this time :)

const schema = reactive([
  // Simple case
  {
    $formkit: 'primeInputNumber',
    name: 'simpleInputNumber',
    label: 'Simple Input Number',
  },
  {
    $formkit: 'primeOutputText',
    name: 'testOutput',
    suffix: 'Basic',
    modelValue: '$simpleInputNumber',
  },
  // Case with Min Value
  {
    $formkit: 'primeInputNumber',
    name: 'numberInputWithMinNumber',
    label: 'Number Input with Min Value',
    min: 10,
  },
  {
    $formkit: 'primeOutputText',
    name: 'testOutput2',
    suffix: 'Min Value Output',
    modelValue: '$numberInputWithMinNumber',
  },
  // Number Input Inheriting from Another Input
  {
    $formkit: 'primeInputNumber',
    name: 'numberInputInheritsFromNumberInputWithMinNumber',
    modelValue: '$numberInputWithMinNumber', // Inherits value from the previous input
    help: 'This input inherits value from the previous input but can be manually changed.',
    placeholder: 'Inherits or manually enter a value',
  },
  {
    $formkit: 'primeOutputText',
    name: 'testOutput3',
    label: 'Inherited Input Output',
    modelValue: '$numberInputInheritsFromNumberInputWithMinNumber',
  },
  // Extensive case
  {
    $formkit: 'primeInputNumber',
    name: 'customizedInputNumber',
    label: 'Customized Input Number',
    placeholder: 'Enter currency',
    useGrouping: true,
    minFractionDigits: 2,
    maxFractionDigits: 4, // Maximum four decimal places
    mode: 'currency', // Switch mode to currency
    currency: 'USD', // Currency in dollars
    locale: 'en-US', // Locale set to US
    showButtons: true, // Show increment/decrement buttons
    buttonLayout: 'horizontal', // Layout for the buttons
    step: 0.01, // Increment by 0.01
  },
  {
    $formkit: 'primeOutputText',
    name: 'testOutput3',
    label: 'Inherited Input Output',
    modelValue: '$customizedInputNumber',
  },
])

Thanks again!

Best regards,
Arnar Arnarson

@ArnarArnar
Copy link
Author

Nope. Sry. On further inspection, this makes the Formkit validation stop working.

@ArnarArnar
Copy link
Author

ArnarArnar commented Sep 24, 2024

Hi again,

I think (yet again) that I found a solution. I may have gone a little overboard with the roundToDecimals function in my earlier proposed solution, so I left it out this time.

// Component - PrimeInputNumber (revised)
watch(
  () => props.context._value,
  (newValue) => {
    if (newValue !== props.context.node.value) { // Only update if the value is different
      props.context?.node.input(newValue)
    }
  }
)

This seems to work well with the min edge case and the validation still works.

Best regards,
Arnar Arnarson

sfxcode added a commit that referenced this issue Sep 24, 2024
@sfxcode
Copy link
Owner

sfxcode commented Sep 24, 2024

Hello Arnar,

try to fix the problems by using some parts of your code, please test if it works for you.

Thanks for your contribution,

Greetings Tom

@ArnarArnar
Copy link
Author

Hey, again. Thanks for adding those changes. Minor issue.

PrimeInputNumber.vue:38 Uncaught (in promise) ReferenceError: watch is not defined
    at setup (PrimeInputNumber.vue:38:5)

Please let me know when to test again.

Best regards,
Arnar Arnarson

@sfxcode
Copy link
Owner

sfxcode commented Sep 25, 2024

Hi, please test again ;-)

Regards,

Tom

@ArnarArnar
Copy link
Author

ArnarArnar commented Sep 25, 2024

I've tested the changes from your repo, and they seem to work. Here are the checks I did:

  • Min and max values now properly update based on selection.
  • Validation works as expected, no issues found.
  • No errors encountered when updating the InputNumber component.
  • The value rounding logic works fine without breaking any other functionality.
  • Watchers behave as expected, updating the state correctly.

Everything appears to be working smoothly!

Thanks again,
Arnar Arnarson

@sfxcode
Copy link
Owner

sfxcode commented Sep 25, 2024

Thanks for testing and your very good work,

Tom

@sfxcode sfxcode closed this as completed Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants