mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-01 03:28:20 +08:00
Merge pull request #181 from catchonme/master
form增加trim,treeSelect增加maxLength/minLength
This commit is contained in:
commit
1702089df6
@ -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` 即可。
|
||||
|
||||
示例:
|
||||
|
||||
|
@ -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
19
docs/renderers/Each.md
Normal 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> "
|
||||
}
|
||||
}
|
||||
```
|
@ -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"
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -226,6 +226,10 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
getWrappedInstance() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
inputRef(ref:any) {
|
||||
this.input = ref;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user