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 代码也伴随 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): 日期范围类型
- [Color](./renderers/Form/Color.md): 颜色选择器
- [Range](./renderers/Form/Range.md): 范围输入框
- [Image](./renderers/Form/Image.md): 图片格式
- [Image](./renderers/Form/Image.md): 图片输
- [File](./renderers/Form/File.md): 文件输入
- [Matrix](./renderers/Form/Matrix.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` 限制图片最小高度。
- `maxWidth` 限制图片最大宽度。
- `maxHeight` 限制图片最大高度。
- `aspectRatio` 限制图片宽高比,格式为浮点型数字,默认 `1``1:1`,如果要设置 `16:9` 请设置 `1.7777777777777777``16 / 9`。。
- **还有更多通用配置请参考** [FormItem](./FormItem.md)
```schema:height="250" scope="form-item"

View File

@ -436,6 +436,13 @@ export default {
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',
path: '/docs/renderers/Tpl',

View File

@ -51,6 +51,8 @@ interface TreeSelectorProps {
rootValue?: any;
cascade?: boolean;
selfDisabledAffectChildren?: boolean;
minLength?: number;
maxLength?: number;
}
interface TreeSelectorState {
@ -292,6 +294,8 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
classnames: cx,
highlightTxt,
data,
maxLength,
minLength
} = this.props;
let childrenChecked = 0;
@ -327,6 +331,16 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
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 ? (
<label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}>
<input

View File

@ -226,6 +226,10 @@ export function registerOptionsControl(config: OptionsConfig) {
}
}
getWrappedInstance() {
return this.input;
}
inputRef(ref:any) {
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>) {
const {
selectedOptions,
@ -344,7 +360,9 @@ export default class TreeSelectControl extends React.Component<TreeSelectProps,
classPrefix: ns,
optionsPlaceholder,
searchable,
autoComplete
autoComplete,
maxLength,
minLength
} = this.props;
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
value={value || ''}
nameField="label"
maxLength={maxLength}
minLength={minLength}
/>
</PopOver>
</Overlay>

View File

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

View File

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

View File

@ -724,4 +724,18 @@ export function chainFunctions(...fns:Array<(...args:Array<any>) => void>):(...a
return (...args:Array<any>) => {
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);
}