Skip to content

Conversation

@James-9696
Copy link
Collaborator

@James-9696 James-9696 commented Feb 27, 2025

PR

修改问题:
当提交表单,校验字段跳转出错的情况(异步校验情况下,比如第一个校验及最后一个校验字段都必填时,点击提交表单,优先提示最后一个字段未填写,而不是第一个字段),是由于未按照props属性的顺序,进行校验。

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Enhanced form validation by introducing a consistent ordering for reported invalid fields. This improvement delivers clearer, more structured error feedback during form submissions, making it easier to identify and resolve issues.

@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2025

Walkthrough

A new function sortFields is introduced in the form module. The function sorts invalid field entries—whether provided as objects or arrays—based on the ordering in the fields array. This sorting is integrated into the validate function, which now sorts both invalidFields and invalidFieldArr before passing them to the callback, modifying the callback's parameters accordingly.

Changes

File Change Summary
packages/…/form/index.ts Added new function sortFields to sort invalid fields (supports objects and arrays) and modified the validate function to use sorted fields in callback.

Sequence Diagram(s)

sequenceDiagram
    participant C as Caller
    participant V as Validate Function
    participant S as sortFields
    participant CB as Callback

    C ->> V: call validate()
    V ->> S: sort(invalidFields, invalidFieldArr)
    S -->> V: return sorted fields
    V ->> CB: invoke callback (with sorted data)
Loading

Suggested reviewers

  • zzcr

Poem

In the code garden, I hopped along,
Sorting fields with a joyful song.
Each invalid bit now lined up neat,
Making validations ever so sweet.
With a twitch of my nose and a happy cheer,
This rabbit celebrates changes here!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/renderless/src/form/index.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-vue".

(The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-vue@latest --save-dev

The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a34887a and f922795.

📒 Files selected for processing (1)
  • packages/renderless/src/form/index.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/renderless/src/form/index.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the bug Something isn't working label Feb 27, 2025
@petercat-assistant
Copy link

  • Walkthrough: This PR addresses a bug in form validation by modifying the sorting logic for form fields in asynchronous situations. It introduces a new function sortFields to ensure fields are sorted correctly before validation callbacks are executed.
  • Changes:
    File Summary
    packages/renderless/src/form/index.ts Added a new function sortFields to sort form fields based on their properties before invoking the validation callback. Updated the callback to use sorted fields.

}
}

const sortFields = (fileds, val) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name fileds seems to be a typo. It should be fields to maintain consistency and avoid confusion.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02e08e9 and 795236e.

📒 Files selected for processing (1)
  • packages/renderless/src/form/index.ts (2 hunks)
🔇 Additional comments (3)
packages/renderless/src/form/index.ts (3)

182-185: Good addition for sorting invalid fields.

The sorting logic ensures consistent order of validation errors based on field declaration order, which will improve the user experience in asynchronous validation scenarios.


197-212: Consider edge cases in the sorting logic.

The current implementation might not handle all scenarios correctly:

  1. What if a field's prop doesn't exist in arrField? It will get an index of -1 which could lead to inconsistent sorting.
  2. The function doesn't handle null or undefined values for val

Consider adding additional checks:

const sortFields = (fileds, val) => {
+  if (val === null || val === undefined) {
+    return val;
+  }
   const arrField = fileds.map((item) => item.prop)
   if (Object.prototype.toString.call(val) === '[object Object]') {
     const keys = Object.keys(val)
-    const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
+    const sortKeys = keys.sort((a, b) => {
+      const aIndex = arrField.indexOf(a);
+      const bIndex = arrField.indexOf(b);
+      // If either field is not found, maintain original order
+      if (aIndex === -1 && bIndex === -1) return 0;
+      if (aIndex === -1) return 1; // Move not found fields to the end
+      if (bIndex === -1) return -1;
+      return aIndex - bIndex;
+    })
     const sortedObject = sortKeys.reduce((acc, index) => {
       acc[index] = val[index]
       return acc
     }, {})
     return sortedObject
   }
   if (Array.isArray(val)) {
-    val.sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
+    val.sort((x, y) => {
+      const xIndex = arrField.indexOf(x);
+      const yIndex = arrField.indexOf(y);
+      // If either field is not found, maintain original order
+      if (xIndex === -1 && yIndex === -1) return 0;
+      if (xIndex === -1) return 1; // Move not found fields to the end
+      if (yIndex === -1) return -1;
+      return xIndex - yIndex;
+    })
     return val
   }
+  return val;
}

187-187:

❓ Verification inconclusive

Modification to callback signature.

The callback now receives an additional third parameter (sortFieldArr). This could potentially break existing code if any consumers expect only two parameters. Consider adding documentation about this change.


🏁 Script executed:

#!/bin/bash
# Check for direct uses of the validate function with custom callbacks
rg "validate\(\s*\([^)]+\)\s*=>" --type ts

Length of output: 44


Callback Signature Change – Please Verify for Compatibility

The callback in the validate function now receives an additional parameter (sortFieldArr), which may impact consumers expecting only two parameters. Although our initial search using an arrow function pattern for validate callbacks did not return any hits, it's unclear if alternate usage patterns exist elsewhere in the codebase.

  • Action Required: Manually verify consumer usages of the validate function (or its callbacks) to ensure that no external component assumes a two-parameter signature. If any such usages are found, update documentation or consider a compatibility fallback.
  • Documentation Update: Add clear documentation about this change to guide future users and developers.

Comment on lines 197 to 212
const sortFields = (fileds, val) => {
const arrField = fileds.map((item) => item.prop)
if (Object.prototype.toString.call(val) === '[object Object]') {
const keys = Object.keys(val)
const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
const sortedObject = sortKeys.reduce((acc, index) => {
acc[index] = val[index]
return acc
}, {})
return sortedObject
}
if (Array.isArray(val)) {
val.sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
return val
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve the new sortFields function with proper types and parameter naming.

The function has several issues that should be addressed:

  1. Typo in parameter name (fileds should be fields)
  2. Missing TypeScript return type
  3. Potential side effect in array sorting
  4. Missing return for non-object/non-array values
-const sortFields = (fileds, val) => {
-  const arrField = fileds.map((item) => item.prop)
+const sortFields = (fields, val): any => {
+  const arrField = fields.map((item) => item.prop)
   if (Object.prototype.toString.call(val) === '[object Object]') {
     const keys = Object.keys(val)
     const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
     const sortedObject = sortKeys.reduce((acc, index) => {
       acc[index] = val[index]
       return acc
     }, {})
     return sortedObject
   }
   if (Array.isArray(val)) {
-    val.sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
-    return val
+    return [...val].sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
   }
+  return val
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sortFields = (fileds, val) => {
const arrField = fileds.map((item) => item.prop)
if (Object.prototype.toString.call(val) === '[object Object]') {
const keys = Object.keys(val)
const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
const sortedObject = sortKeys.reduce((acc, index) => {
acc[index] = val[index]
return acc
}, {})
return sortedObject
}
if (Array.isArray(val)) {
val.sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
return val
}
}
const sortFields = (fields, val): any => {
const arrField = fields.map((item) => item.prop)
if (Object.prototype.toString.call(val) === '[object Object]') {
const keys = Object.keys(val)
const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
const sortedObject = sortKeys.reduce((acc, index) => {
acc[index] = val[index]
return acc
}, {})
return sortedObject
}
if (Array.isArray(val)) {
return [...val].sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
}
return val
}

@zzcr
Copy link
Member

zzcr commented Feb 27, 2025

这个光看标题也不知道在解决什么问题,描述可以用中文描述清楚点

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically.


Just looking at the title, you don't know what the problem is being solved. The description can be described clearly in Chinese.

@James-9696
Copy link
Collaborator Author

这个光看标题也不知道在解决什么问题,描述可以用中文描述清楚点

修改问题:
当提交表单,校验字段跳转出错的情况(异步校验情况下,比如第一个校验及最后一个校验字段都必填时,点击提交表单,优先提示最后一个字段未填写,而不是第一个字段),是由于未按照props属性的顺序,进行校验。

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically.


Just looking at the title, you don’t know what problems you are solving. The description can be described clearly in Chinese.

Modify the problem:
When submitting the form and the verification field jumps error (in the case of asynchronous verification, for example, when the first verification and the last verification field are required, click Submit the form to indicate that the last field is not filled in instead of the first field), it is because the verification is not performed in the order of the props attributes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/renderless/src/form/index.ts (3)

183-186: Performance optimization opportunity for field sorting.

The current implementation sorts fields during each validation callback, which is inefficient in an asynchronous loop. Instead of sorting during each iteration, consider only sorting once at the end of the validation process to improve performance from O(N²logN) to O(NlogN).

state.fields.forEach((field) => {
  field.validate('', (message, field) => {
    if (message) {
      valid = false
    }

    invalidFields = merge({}, invalidFields, field)

    if (field) {
      Object.keys(field).forEach((item) => invalidFieldArr.push(item))
    }

    if (typeof callback === 'function' && ++count === state.fields.length) {
-      // 排序
-      const sortField = sortFields(state.fields, invalidFields)
-      const sortFieldArr = sortFields(state.fields, invalidFieldArr)
-      callback(valid, sortField, sortFieldArr)
+      // Sort only once at the end
+      const sortedInvalidFields = sortFields(state.fields, invalidFields)
+      const sortedInvalidFieldArr = sortFields(state.fields, invalidFieldArr)
+      callback(valid, sortedInvalidFields, sortedInvalidFieldArr)
    }
  })
})

183-183: Translate Chinese comment for better maintainability.

Consider translating the Chinese comment "排序" to English (e.g., "Sort fields") to maintain consistency with the rest of the codebase and improve accessibility for all contributors.

-      // 排序
+      // Sort fields based on their declaration order

196-211: Missing TypeScript interface for the sortFields function.

The function lacks proper type definitions for its parameters and return value, which can lead to type errors and unexpected behavior. Consider defining explicit interfaces for the parameters and return type.

+interface FormField {
+  prop: string;
+  [key: string]: any;
+}
+
+/**
+ * Sorts field entries based on their order in the fields array
+ * @param fields Form field definitions containing prop property
+ * @param val Object or array of field entries to be sorted
+ * @returns Sorted object, array, or the original value if not sortable
+ */
-const sortFields = (fileds, val) => {
+const sortFields = (fields: FormField[], val: any): any => {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 795236e and a34887a.

📒 Files selected for processing (1)
  • packages/renderless/src/form/index.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)
🔇 Additional comments (2)
packages/renderless/src/form/index.ts (2)

196-211: Function typo and missing implementation details.

The function name fileds is misspelled and contains several implementation issues:

  1. Missing TypeScript type definitions
  2. Mutating the original array with direct sorting
  3. No handling for non-object/non-array values
  4. No explicit TypeScript return type

Apply the following improvements:

-const sortFields = (fileds, val) => {
-  const arrField = fileds.map((item) => item.prop)
+const sortFields = (fields, val): any => {
+  const arrField = fields.map((item) => item.prop)
   if (Object.prototype.toString.call(val) === '[object Object]') {
     const keys = Object.keys(val)
     const sortKeys = keys.sort((a, b) => arrField.indexOf(a) - arrField.indexOf(b))
     const sortedObject = sortKeys.reduce((acc, index) => {
       acc[index] = val[index]
       return acc
     }, {})
     return sortedObject
   }
   if (Array.isArray(val)) {
-    val.sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
-    return val
+    return [...val].sort((x, y) => arrField.indexOf(x) - arrField.indexOf(y))
   }
+  return val
}

152-156:

❓ Verification inconclusive

Verify Promise handling with the new callback parameters.

The Promise handling in the validate function might not properly handle the new callback signature with three parameters. The promise resolution currently only considers the first parameter (valid), but the sorting changes have modified the callback signature.


🏁 Script executed:

#!/bin/bash
# Check if there are any usages of the validate method that rely on Promise resolution
# to ensure they work correctly with the modified callback parameters

rg -A 2 "validate\(\)" --type ts --no-filename
echo "--------------------"
rg -A 2 "validate\(" --type ts --no-filename | grep -v "validate\(\)"

Length of output: 1518


Action: Verify that the Promise resolution in validate correctly handles the new three-parameter callback signature.

The current implementation in packages/renderless/src/form/index.ts (lines 152–156) only inspects the first argument (valid). With the updated callback now receiving three parameters, please double-check that:

  • Any additional arguments that influence validation outcomes (e.g., error details or supplementary data) are either correctly propagated or intentionally ignored.
  • Consumers of the validate() promise (e.g., the chain using .then(() => true).catch(() => false)) are updated if they rely on information from the extra parameters, or that a comment is added to clarify the design decision.

@zzcr zzcr merged commit 989072d into dev Mar 7, 2025
5 checks passed
@kagol kagol deleted the fix-form-cmp-0227 branch April 14, 2025 12:26
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

Successfully merging this pull request may close these issues.

5 participants