Merge pull request #181 from catchonme/master

form增加trim,treeSelect增加maxLength/minLength
This commit is contained in:
liaoxuezhi 2019-08-22 10:45:13 +08:00 committed by GitHub
commit 1702089df6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 98 additions and 6 deletions

View File

@ -222,7 +222,7 @@ class MyComponent extends React.Component<any, any> {
注意:以上的 SDK 地址是一个页面跳转,会跳转到一个 CDN 地址,而且每次跳转都是最新的版本,随着 amis 的升级这个地址会一直变动,如果你的页面已经完成功能回归,请直接使用某个固定地址,这样才不会因为 amis 升级而导致你的页面不可用。 注意:以上的 SDK 地址是一个页面跳转,会跳转到一个 CDN 地址,而且每次跳转都是最新的版本,随着 amis 的升级这个地址会一直变动,如果你的页面已经完成功能回归,请直接使用某个固定地址,这样才不会因为 amis 升级而导致你的页面不可用。
另外sdk 代码也伴随 npm 一起发布了,不用 CDN 版本直接替换成npm包里面的 `amis/sdk/sdk.js``amis/sdk/sdk.css` 即可。 另外sdk 代码也伴随 npm 一起发布了,不使用 CDN 版本直接替换成npm包里面的 `amis/sdk/sdk.js``amis/sdk/sdk.css` 即可。
示例: 示例:

View File

@ -40,7 +40,7 @@ amis 页面是通过 JSON 配置出来的,是由一个一个渲染模型组成
- [Date-Range](./renderers/Form/Date-Range.md): 日期范围类型 - [Date-Range](./renderers/Form/Date-Range.md): 日期范围类型
- [Color](./renderers/Form/Color.md): 颜色选择器 - [Color](./renderers/Form/Color.md): 颜色选择器
- [Range](./renderers/Form/Range.md): 范围输入框 - [Range](./renderers/Form/Range.md): 范围输入框
- [Image](./renderers/Form/Image.md): 图片格式 - [Image](./renderers/Form/Image.md): 图片输
- [File](./renderers/Form/File.md): 文件输入 - [File](./renderers/Form/File.md): 文件输入
- [Matrix](./renderers/Form/Matrix.md): 矩阵类型的输入框 - [Matrix](./renderers/Form/Matrix.md): 矩阵类型的输入框
- [Tree](./renderers/Form/Tree.md): 树形结构输入框 - [Tree](./renderers/Form/Tree.md): 树形结构输入框

19
docs/renderers/Each.md Normal file
View File

@ -0,0 +1,19 @@
## Each
基于现有变量循环输出渲染器
- `type` 请设置 `each`
- `value` 格式为数组。
- `items` 使用`value`中的数据,循环输出渲染器。
```schema:height="160" scope="body"
{
"type": "each",
"value": ["A", "B", "C"],
"items": {
"type": "tpl",
"tpl": "<span class='label label-default'><%= data.item %></span> "
}
}
```

View File

@ -25,6 +25,7 @@
- `minHeight` 限制图片最小高度。 - `minHeight` 限制图片最小高度。
- `maxWidth` 限制图片最大宽度。 - `maxWidth` 限制图片最大宽度。
- `maxHeight` 限制图片最大高度。 - `maxHeight` 限制图片最大高度。
- `aspectRatio` 限制图片宽高比,格式为浮点型数字,默认 `1``1:1`,如果要设置 `16:9` 请设置 `1.7777777777777777``16 / 9`。。
- **还有更多通用配置请参考** [FormItem](./FormItem.md) - **还有更多通用配置请参考** [FormItem](./FormItem.md)
```schema:height="250" scope="form-item" ```schema:height="250" scope="form-item"

View File

@ -436,6 +436,13 @@ export default {
cb(null, makeMarkdownRenderer(doc)); cb(null, makeMarkdownRenderer(doc));
}), }),
}, },
{
label: 'Each',
path: '/docs/renderers/Each',
getComponent: (location, cb) => require(['../../docs/renderers/Each.md'], (doc) => {
cb(null, makeMarkdownRenderer(doc));
}),
},
{ {
label: 'Tpl', label: 'Tpl',
path: '/docs/renderers/Tpl', path: '/docs/renderers/Tpl',

View File

@ -51,6 +51,8 @@ interface TreeSelectorProps {
rootValue?: any; rootValue?: any;
cascade?: boolean; cascade?: boolean;
selfDisabledAffectChildren?: boolean; selfDisabledAffectChildren?: boolean;
minLength?: number;
maxLength?: number;
} }
interface TreeSelectorState { interface TreeSelectorState {
@ -292,6 +294,8 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
classnames: cx, classnames: cx,
highlightTxt, highlightTxt,
data, data,
maxLength,
minLength
} = this.props; } = this.props;
let childrenChecked = 0; let childrenChecked = 0;
@ -327,6 +331,16 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
let nodeDisabled = !!uncheckable || !!disabled || selfDisabled; let nodeDisabled = !!uncheckable || !!disabled || selfDisabled;
if (
!nodeDisabled
&& (
(maxLength && !selfChecked && this.state.value.length >= maxLength)
|| (minLength && selfChecked && this.state.value.length <= minLength)
)
) {
nodeDisabled = true;
}
const checkbox: JSX.Element | null = multiple ? ( const checkbox: JSX.Element | null = multiple ? (
<label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}> <label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}>
<input <input

View File

@ -226,6 +226,10 @@ export function registerOptionsControl(config: OptionsConfig) {
} }
} }
getWrappedInstance() {
return this.input;
}
inputRef(ref:any) { inputRef(ref:any) {
this.input = ref; this.input = ref;
} }

View File

@ -122,6 +122,22 @@ export default class TreeSelectControl extends React.Component<TreeSelectProps,
} }
} }
validate():any {
const {
value,
minLength,
maxLength,
delimiter
} = this.props;
let curValue = Array.isArray(value) ? value : (value ? value : '').split(delimiter || ',');
if (minLength && curValue.length < minLength) {
return `已选择数量低于设定的最小个数${minLength},请选择更多的选项。`;
} else if (maxLength && curValue.length > maxLength) {
return `已选择数量超出设定的最大个数${maxLength},请取消选择超出的选项。`;
}
}
removeItem(index:number, e?: React.MouseEvent<HTMLElement>) { removeItem(index:number, e?: React.MouseEvent<HTMLElement>) {
const { const {
selectedOptions, selectedOptions,
@ -344,7 +360,9 @@ export default class TreeSelectControl extends React.Component<TreeSelectProps,
classPrefix: ns, classPrefix: ns,
optionsPlaceholder, optionsPlaceholder,
searchable, searchable,
autoComplete autoComplete,
maxLength,
minLength
} = this.props; } = this.props;
let filtedOptions = !isEffectiveApi(autoComplete) && searchable && this.state.inputValue ? this.filterOptions(options, this.state.inputValue) : options; let filtedOptions = !isEffectiveApi(autoComplete) && searchable && this.state.inputValue ? this.filterOptions(options, this.state.inputValue) : options;
@ -389,6 +407,8 @@ export default class TreeSelectControl extends React.Component<TreeSelectProps,
hideRoot hideRoot
value={value || ''} value={value || ''}
nameField="label" nameField="label"
maxLength={maxLength}
minLength={minLength}
/> />
</PopOver> </PopOver>
</Overlay> </Overlay>

View File

@ -89,6 +89,7 @@ export interface FormProps extends RendererProps, FormSchema {
canAccessSuperData: boolean; canAccessSuperData: boolean;
persistData: boolean; // 开启本地缓存 persistData: boolean; // 开启本地缓存
clearPersistDataAfterSubmit: boolean; // 提交成功后清空本地缓存 clearPersistDataAfterSubmit: boolean; // 提交成功后清空本地缓存
trimValues?: boolean;
onInit?: (values:object) => any; onInit?: (values:object) => any;
onReset?: (values:object) => void; onReset?: (values:object) => void;
onSubmit?: (values:object, action:any) => any; onSubmit?: (values:object, action:any) => any;
@ -486,9 +487,14 @@ export default class Form extends React.Component<FormProps, object> {
target, target,
env, env,
onChange, onChange,
clearPersistDataAfterSubmit clearPersistDataAfterSubmit,
trimValues
} = this.props; } = this.props;
if (trimValues) {
store.trimValues();
}
if (Array.isArray(action.required) && action.required.length) { if (Array.isArray(action.required) && action.required.length) {
return store return store
.validateFields(action.required) .validateFields(action.required)
@ -1029,7 +1035,7 @@ export class FormRenderer extends Form {
} }
const component = scoped.getComponentByName(name); const component = scoped.getComponentByName(name);
component && component.receive && component && component.receive(values, subPath); component && component.receive && component.receive(values, subPath);
return; return;
} }

View File

@ -28,7 +28,8 @@ import {
difference, difference,
guid, guid,
isObject, isObject,
isEmpty isEmpty,
mapObject
} from '../utils/helper'; } from '../utils/helper';
import { IComboStore } from "./combo"; import { IComboStore } from "./combo";
import isEqual = require('lodash/isEqual'); import isEqual = require('lodash/isEqual');
@ -180,6 +181,11 @@ export const FormStore = ServiceStore
self.data = data; self.data = data;
} }
function trimValues() {
let data = mapObject(self.data, (item:any) => typeof item === 'string' ? item.trim() : item);
self.updateData(data);
}
function syncOptions() { function syncOptions() {
self.items.forEach(item => item.syncOptions()); self.items.forEach(item => item.syncOptions());
} }
@ -410,6 +416,7 @@ export const FormStore = ServiceStore
setInited, setInited,
setValues, setValues,
setValueByName, setValueByName,
trimValues,
submit, submit,
validate, validate,
validateFields, validateFields,

View File

@ -725,3 +725,17 @@ export function chainFunctions(...fns:Array<(...args:Array<any>) => void>):(...a
fns.forEach(fn => fn && fn(...args)); fns.forEach(fn => fn && fn(...args));
} }
} }
export function mapObject(value: any, fn: Function): any {
if (Array.isArray(value)) {
return value.map(item => mapObject(item, fn));
}
if (isObject(value)) {
let tmpValue = {...value};
Object.keys(tmpValue).forEach(key => {
(tmpValue as PlainObject)[key] = mapObject((tmpValue as PlainObject)[key], fn);
});
return tmpValue;
}
return fn(value);
}