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: Field support messageVariables #80

Merged
merged 2 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions examples/validate-perf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ValidateMessages } from '../src/interface';

const myMessages: ValidateMessages = {
default: '${name} 看起来怪怪的……',
required: '你需要一个 ${name}',
required: '你需要一个 ${displayName}',
types: {
number: '嗨,这个 ${name} 不是一个合格的 ${type}',
},
Expand Down Expand Up @@ -46,13 +46,18 @@ export default class Demo extends React.Component {
validateMessages={myMessages}
initialValues={{ remember: true }}
>
<LabelField name="password" rules={[{ required: true }]}>
<LabelField
name="password"
messageVariables={{ displayName: '密码' }}
rules={[{ required: true }]}
>
<Input placeholder="password" />
</LabelField>

<LabelField
name="password2"
dependencies={['password']}
messageVariables={{ displayName: '密码2' }}
rules={[
{ required: true },
({ getFieldValue }) => ({
Expand All @@ -71,6 +76,7 @@ export default class Demo extends React.Component {
<LabelField
name="field"
label="Full of rules"
messageVariables={{ displayName: '字段' }}
rules={[
{ required: true },
{ required: true, message: <h1>我是 ReactNode</h1> },
Expand Down
12 changes: 10 additions & 2 deletions src/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface FieldProps {
validateTrigger?: string | string[] | false;
validateFirst?: boolean;
valuePropName?: string;
messageVariables?: Record<string, string>;
onReset?: () => void;
}

Expand Down Expand Up @@ -272,7 +273,7 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
};

public validateRules = (options?: ValidateOptions) => {
const { validateFirst } = this.props;
const { validateFirst = false, messageVariables } = this.props;
const { triggerName } = (options || {}) as ValidateOptions;
const namePath = this.getNamePath();

Expand All @@ -288,7 +289,14 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
});
}

const promise = validateRules(namePath, this.getValue(), filteredRules, options, validateFirst);
const promise = validateRules(
namePath,
this.getValue(),
filteredRules,
options,
validateFirst,
messageVariables,
);
this.validatePromise = promise;
this.errors = [];

Expand Down
20 changes: 15 additions & 5 deletions src/utils/validateUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function convertMessages(
messages: ValidateMessages,
name: string,
rule: RuleObject,
messageVariables?: Record<string, string>,
): ValidateMessages {
const kv = {
...(rule as Record<string, string | number>),
Expand All @@ -48,7 +49,7 @@ function convertMessages(
Object.keys(source).forEach(ruleName => {
const value = source[ruleName];
if (typeof value === 'string') {
target[ruleName] = replaceFunc(value);
target[ruleName] = replaceFunc(value, messageVariables);
} else if (value && typeof value === 'object') {
target[ruleName] = {};
fillTemplate(value, target[ruleName]);
Expand All @@ -69,6 +70,7 @@ async function validateRule(
value: StoreValue,
rule: RuleObject,
options: ValidateOptions,
messageVariables?: Record<string, string>,
): Promise<string[]> {
const cloneRule = { ...rule };
// We should special handle array validate
Expand All @@ -82,7 +84,12 @@ async function validateRule(
[name]: [cloneRule],
});

const messages: ValidateMessages = convertMessages(options.validateMessages, name, cloneRule);
const messages: ValidateMessages = convertMessages(
options.validateMessages,
name,
cloneRule,
messageVariables,
);
validator.messages(messages);

let result = [];
Expand All @@ -106,7 +113,7 @@ async function validateRule(
if (!result.length && subRuleField) {
const subResults: string[][] = await Promise.all(
(value as StoreValue[]).map((subValue: StoreValue, i: number) =>
validateRule(`${name}.${i}`, subValue, subRuleField, options),
validateRule(`${name}.${i}`, subValue, subRuleField, options, messageVariables),
),
);

Expand All @@ -125,7 +132,8 @@ export function validateRules(
value: StoreValue,
rules: RuleObject[],
options: ValidateOptions,
validateFirst?: boolean,
validateFirst: boolean,
messageVariables?: Record<string, string>,
) {
const name = namePath.join('.');

Expand Down Expand Up @@ -180,7 +188,9 @@ export function validateRules(
};
});

const rulePromises = filledRules.map(rule => validateRule(name, value, rule, options));
const rulePromises = filledRules.map(rule =>
validateRule(name, value, rule, options, messageVariables),
);

const summaryPromise: Promise<string[]> = (validateFirst
? finishOnFirstFailed(rulePromises)
Expand Down
18 changes: 16 additions & 2 deletions tests/validate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ describe('Form.Validate', () => {
});

describe('validateMessages', () => {
function renderForm(messages) {
function renderForm(messages, fieldProps = {}) {
return mount(
<Form validateMessages={messages}>
<InfoField name="username" rules={[{ required: true }]} />
<InfoField name="username" rules={[{ required: true }]} {...fieldProps} />
</Form>,
);
}
Expand All @@ -66,6 +66,20 @@ describe('Form.Validate', () => {
await changeValue(wrapper, '');
matchError(wrapper, 'Bamboo & Light');
});

it('messageVariables', async () => {
const wrapper = renderForm(
{ required: "You miss '${label}'!" },
Copy link
Member

@afc163 afc163 Feb 11, 2020

Choose a reason for hiding this comment

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

${} 万一这个字符串写成 ` 的格式就会很复杂。

Copy link
Member

Choose a reason for hiding this comment

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

const username = '姓名';

...

{ required: `miss \${label} ${username}` },

Copy link
Contributor

Choose a reason for hiding this comment

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

${} 会被转化成字符串拼接的,应该没什么影响

Copy link
Member

@afc163 afc163 Feb 11, 2020

Choose a reason for hiding this comment

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

写起来是不是比较难看?

Copy link
Contributor

@chenshuai2144 chenshuai2144 Feb 11, 2020

Choose a reason for hiding this comment

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

\${label} 有一些理解成本,第一眼不知道是什么东西

Copy link
Member Author

@zombieJ zombieJ Feb 12, 2020

Choose a reason for hiding this comment

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

${xxx} is used for validateMessages for static message template:

const myMessages: ValidateMessages = {
  default: '${name} 看起来怪怪的……',
  required: '你需要一个 ${name}',
  types: {
    number: '嗨,这个 ${name} 不是一个合格的 ${type}',
  },
  enum: '${name} 不在 ${enum} 中呢',
  whitespace: '${name} 不可以是空的啦',
  pattern: {
    mismatch: '${name} 并不符合格式:${pattern}',
  },
};

If user use `, it's no need to use ${xxx}.

Copy link
Member

@afc163 afc163 Feb 12, 2020

Choose a reason for hiding this comment

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

我的意思是如果这个字符串里需要用到别的变量(比如 username)改造成 ` 写法后,原有的 ${label} 写法就会和新的 ${username} 混淆在一起,需要转义。

Copy link
Member Author

Choose a reason for hiding this comment

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

现在的 form 已经是支持 ${xxx} 了,这个 PR 只是拓展自定义变量的能力。

Current form is already support ${xxx}. This PR is aim to extends the ability of message variables.

{
messageVariables: {
label: 'Light&Bamboo',
},
},
);

await changeValue(wrapper, '');
matchError(wrapper, "You miss 'Light&Bamboo'!");
});
});

describe('customize validator', () => {
Expand Down