Autocomplete: add value-key (#7671)

* Autocomplete: add value-key

* fix autocomplete test
pull/7675/head
杨奕 2017-10-24 02:24:35 -05:00 committed by GitHub
parent 14ecf86c55
commit 4517e3d9be
12 changed files with 86 additions and 86 deletions

18
build/deploy-faas.sh Normal file
View File

@ -0,0 +1,18 @@
#! /bin/sh
mkdir temp_web
npm run deploy:build
cd temp_web
git clone -b gh-pages https://github.com/ElemeFE/element.git && cd element
# build sub folder
SUB_FOLDER='2.0'
mkdir $SUB_FOLDER
# rm -rf *.js *.css *.map static
rm -rf $SUB_FOLDER/**
# cp -rf ../../examples/element-ui/** .
cp -rf ../../examples/element-ui/** $SUB_FOLDER/
cp -rf ../../examples/element-ui/versions.json .
cd ../..
# deploy domestic site
faas deploy alpha

View File

@ -16,7 +16,7 @@ then
echo "Releasing theme-chalk $VERSION ..." echo "Releasing theme-chalk $VERSION ..."
cd packages/theme-chalk cd packages/theme-chalk
npm version $VERSION --message "[release] $VERSION" npm version $VERSION --message "[release] $VERSION"
npm publish --tag next npm publish
cd ../.. cd ../..
# commit # commit

View File

@ -50,6 +50,7 @@
.container { .container {
box-sizing: border-box; box-sizing: border-box;
width: auto;
} }
.footer-main { .footer-main {

View File

@ -657,7 +657,7 @@ Attribute | Description | Type | Options | Default
|----| ----| ----| ---- | -----| |----| ----| ----| ---- | -----|
|placeholder| the placeholder of Autocomplete| string | — | — | |placeholder| the placeholder of Autocomplete| string | — | — |
|disabled | whether Autocomplete is disabled | boolean | — | false| |disabled | whether Autocomplete is disabled | boolean | — | false|
| props | configuration options, see the following table | object | — | — | | valueKey | key name of the input suggestion object for display | string | — | value |
|icon | icon name | string | — | — | |icon | icon name | string | — | — |
|value | binding value | string | — | — | |value | binding value | string | — | — |
| debounce | debounce delay when typing, in milliseconds | number | — | 300 | | debounce | debounce delay when typing, in milliseconds | number | — | 300 |
@ -669,12 +669,6 @@ Attribute | Description | Type | Options | Default
| select-when-unmatched | whether to emit a `select` event on enter when there is no autocomplete match | boolean | — | false | | select-when-unmatched | whether to emit a `select` event on enter when there is no autocomplete match | boolean | — | false |
| label | label text | string | — | — | | label | label text | string | — | — |
### props
| Attribute | Description | Type | Accepted Values | Default |
| --------- | ----------------- | ------ | ------ | ------ |
| label | specify which key of option object is used as the option's label | string | — | value |
| value | specify which key of option object is used as the option's value | string | — | value |
### Autocomplete slots ### Autocomplete slots
| Name | Description | | Name | Description |

View File

@ -232,18 +232,19 @@
resetChecked() { resetChecked() {
this.$refs.tree.setCheckedKeys([]); this.$refs.tree.setCheckedKeys([]);
}, },
append(store, data) { append(data) {
const newChild = { id: id++, label: 'testtest', children: [] }; const newChild = { id: id++, label: 'testtest', children: [] };
store.append(newChild, data); if (!data.children) {
data.children = data.children || []; this.$set(data, 'children', []);
}
data.children.push(newChild); data.children.push(newChild);
}, },
remove(store, node, data) { remove(node, data) {
const parent = node.parent; const parent = node.parent;
const index = parent.data.children.findIndex(d => d.id === data.id); const children = parent.data.children || parent.data;
parent.data.children.splice(index, 1); const index = children.findIndex(d => d.id === data.id);
store.remove(data); children.splice(index, 1);
}, },
renderContent(h, { node, data, store }) { renderContent(h, { node, data, store }) {
@ -253,8 +254,8 @@
<span>{node.label}</span> <span>{node.label}</span>
</span> </span>
<span> <span>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.append(store, data) }>Append</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.append(data) }>Append</el-button>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(store, node, data) }>Delete</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button>
</span> </span>
</span>); </span>);
}, },
@ -270,6 +271,7 @@
data, data,
data2, data2,
data3, data3,
data4: JSON.parse(JSON.stringify(data2)),
regions, regions,
defaultProps, defaultProps,
props, props,
@ -683,14 +685,10 @@ Tree nodes can be initially expanded or checked
### Custom node content ### Custom node content
The content of tree nodes can be customized, so you can add icons or buttons as you will The content of tree nodes can be customized, so you can add icons or buttons as you will
:::warning
`Append` and `remove` do not change `data`
:::
::: demo Use `render-content` to assign a render function that returns the content of tree nodes. See Vue's documentation for a detailed introduction of render functions. Note that this demo can't run in jsfiddle because it doesn't support JSX syntax. In a real project, `render-content` will work if relevant dependencies are correctly configured. ::: demo Use `render-content` to assign a render function that returns the content of tree nodes. See Vue's documentation for a detailed introduction of render functions. Note that this demo can't run in jsfiddle because it doesn't support JSX syntax. In a real project, `render-content` will work if relevant dependencies are correctly configured.
```html ```html
<el-tree <el-tree
:data="data2" :data="data4"
:props="defaultProps" :props="defaultProps"
show-checkbox show-checkbox
node-key="id" node-key="id"
@ -705,7 +703,7 @@ The content of tree nodes can be customized, so you can add icons or buttons as
export default { export default {
data() { data() {
return { return {
data2: [{ data4: [{
id: 1, id: 1,
label: 'Level one 1', label: 'Level one 1',
children: [{ children: [{
@ -748,18 +746,19 @@ The content of tree nodes can be customized, so you can add icons or buttons as
}, },
methods: { methods: {
append(store, data) { append(data) {
const newChild = { id: id++, label: 'testtest', children: [] }; const newChild = { id: id++, label: 'testtest', children: [] };
store.append(newChild, data); // need change data by yourself if (!data.children) {
data.children = data.children || []; this.$set(data, 'children', []);
}
data.children.push(newChild); data.children.push(newChild);
}, },
remove(store, node, data) { remove(node, data) {
const parent = node.parent; const parent = node.parent;
const index = parent.data.children.findIndex(d => d.id === data.id); const children = parent.data.children || parent.data;
parent.data.children.splice(index, 1); const index = children.findIndex(d => d.id === data.id);
store.remove(data); // need change data by yourself children.splice(index, 1);
}, },
renderContent(h, { node, data, store }) { renderContent(h, { node, data, store }) {
@ -769,8 +768,8 @@ The content of tree nodes can be customized, so you can add icons or buttons as
<span>{node.label}</span> <span>{node.label}</span>
</span> </span>
<span> <span>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.append(store, data) }>Append</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.append(data) }>Append</el-button>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(store, node, data) }>Delete</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button>
</span> </span>
</span>); </span>);
} }
@ -939,7 +938,7 @@ Only one node among the same level can be expanded at one time.
| node-key | unique identity key name for nodes, its value should be unique across the whole tree | string | — | — | | node-key | unique identity key name for nodes, its value should be unique across the whole tree | string | — | — |
| props | configuration options, see the following table | object | — | — | | props | configuration options, see the following table | object | — | — |
| load | method for loading subtree data | function(node, resolve) | — | — | | load | method for loading subtree data | function(node, resolve) | — | — |
| render-content | render function for tree node | Function(h, { node } | — | — | | render-content | render function for tree node | Function(h, { node, data, store } | — | — |
| highlight-current | whether current node is highlighted | boolean | — | false | | highlight-current | whether current node is highlighted | boolean | — | false |
| default-expand-all | whether to expand all nodes by default | boolean | — | false | | default-expand-all | whether to expand all nodes by default | boolean | — | false |
| expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | — | true | | | expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | — | true | |

View File

@ -816,7 +816,7 @@ export default {
|------------- |---------------- |---------------- |---------------------- |-------- | |------------- |---------------- |---------------- |---------------------- |-------- |
| placeholder | 输入框占位文本 | string | — | — | | placeholder | 输入框占位文本 | string | — | — |
| disabled | 禁用 | boolean | — | false | | disabled | 禁用 | boolean | — | false |
| props | 配置选项,具体见下表 | object | — | — | | valueKey | 输入建议对象中用于显示的键名 | string | — | value |
| value | 必填值,输入绑定值 | string | — | — | | value | 必填值,输入绑定值 | string | — | — |
| debounce | 获取输入建议的去抖延时 | number | — | 300 | | debounce | 获取输入建议的去抖延时 | number | — | 300 |
| fetch-suggestions | 返回输入建议的方法,仅当你的输入建议数据 resolve 时,通过调用 callback(data:[]) 来返回它 | Function(queryString, callback) | — | — | | fetch-suggestions | 返回输入建议的方法,仅当你的输入建议数据 resolve 时,通过调用 callback(data:[]) 来返回它 | Function(queryString, callback) | — | — |
@ -826,12 +826,6 @@ export default {
| select-when-unmatched | 在输入没有任何匹配建议的情况下,按下回车是否触发 `select` 事件 | boolean | — | false | | select-when-unmatched | 在输入没有任何匹配建议的情况下,按下回车是否触发 `select` 事件 | boolean | — | false |
| label | 输入框关联的label文字 | string | — | — | | label | 输入框关联的label文字 | string | — | — |
### props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ----------------- | ------ | ------ | ------ |
| value | 指定选项的值为选项对象的某个属性值 | string | — | value |
| label | 指定选项标签为选项对象的某个属性值 | string | — | value |
### Autocomplete slots ### Autocomplete slots
| name | 说明 | | name | 说明 |
|------|--------| |------|--------|

View File

@ -232,29 +232,30 @@
resetChecked() { resetChecked() {
this.$refs.tree.setCheckedKeys([]); this.$refs.tree.setCheckedKeys([]);
}, },
append(store, data) { append(data) {
const newChild = { id: id++, label: 'testtest', children: [] }; const newChild = { id: id++, label: 'testtest', children: [] };
store.append(newChild, data); if (!data.children) {
data.children = data.children || []; this.$set(data, 'children', []);
}
data.children.push(newChild); data.children.push(newChild);
}, },
remove(store, node, data) { remove(node, data) {
const parent = node.parent; const parent = node.parent;
const index = parent.data.children.findIndex(d => d.id === data.id); const children = parent.data.children || parent.data;
parent.data.children.splice(index, 1); const index = children.findIndex(d => d.id === data.id);
store.remove(data); children.splice(index, 1);
}, },
renderContent(h, { node, data, store }) { renderContent(h, { node, data }) {
return ( return (
<span style="flex: 1; display: flex; align-items: center; justify-content: space-between; font-size: 14px; padding-right: 8px;"> <span style="flex: 1; display: flex; align-items: center; justify-content: space-between; font-size: 14px; padding-right: 8px;">
<span> <span>
<span>{node.label}</span> <span>{node.label}</span>
</span> </span>
<span> <span>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.append(store, data) }>Append</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.append(data) }>Append</el-button>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(store, node, data) }>Delete</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button>
</span> </span>
</span>); </span>);
}, },
@ -270,6 +271,7 @@
data, data,
data2, data2,
data3, data3,
data4: JSON.parse(JSON.stringify(data2)),
regions, regions,
defaultProps, defaultProps,
props, props,
@ -682,14 +684,10 @@
### 自定义节点内容 ### 自定义节点内容
节点的内容支持自定义,可以在节点区添加按钮或图标等内容 节点的内容支持自定义,可以在节点区添加按钮或图标等内容
:::warning
`append``remove` 方法不会改变 `data` 上的数据
:::
::: demo 使用`render-content`指定渲染函数,该函数返回需要的节点区内容即可。渲染函数的用法请参考 Vue 文档。注意:由于 jsfiddle 不支持 JSX 语法,所以本例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。 ::: demo 使用`render-content`指定渲染函数,该函数返回需要的节点区内容即可。渲染函数的用法请参考 Vue 文档。注意:由于 jsfiddle 不支持 JSX 语法,所以本例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。
```html ```html
<el-tree <el-tree
:data="data2" :data="data4"
:props="defaultProps" :props="defaultProps"
show-checkbox show-checkbox
node-key="id" node-key="id"
@ -704,7 +702,7 @@
export default { export default {
data() { data() {
return { return {
data2: [{ data4: [{
id: 1, id: 1,
label: '一级 1', label: '一级 1',
children: [{ children: [{
@ -747,18 +745,19 @@
}, },
methods: { methods: {
append(store, data) { append(data) {
const newChild = { id: id++, label: 'testtest', children: [] }; const newChild = { id: id++, label: 'testtest', children: [] };
store.append(newChild, data); // append 不会改变 data if (!data.children) {
data.children = data.children || []; this.$set(data, 'children', []);
}
data.children.push(newChild); data.children.push(newChild);
}, },
remove(store, node, data) { remove(node, data) {
const parent = node.parent; const parent = node.parent;
const index = parent.data.children.findIndex(d => d.id === data.id); const children = parent.data.children || parent.data;
parent.data.children.splice(index, 1); const index = children.findIndex(d => d.id === data.id);
store.remove(data); // remove 不会改变 data children.splice(index, 1);
}, },
renderContent(h, { node, data, store }) { renderContent(h, { node, data, store }) {
@ -768,8 +767,8 @@
<span>{node.label}</span> <span>{node.label}</span>
</span> </span>
<span> <span>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.append(store, data) }>Append</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.append(data) }>Append</el-button>
<el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(store, node, data) }>Delete</el-button> <el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button>
</span> </span>
</span>); </span>);
} }
@ -938,7 +937,7 @@
| node-key | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | String | — | — | | node-key | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | String | — | — |
| props | 配置选项,具体看下表 | object | — | — | | props | 配置选项,具体看下表 | object | — | — |
| load | 加载子树数据的方法 | function(node, resolve) | — | — | | load | 加载子树数据的方法 | function(node, resolve) | — | — |
| render-content | 树节点的内容区的渲染 Function | Function(h, { node } | — | — | | render-content | 树节点的内容区的渲染 Function | Function(h, { node, data, store } | — | — |
| highlight-current | 是否高亮当前选中节点,默认值是 false。 | boolean | — | false | | highlight-current | 是否高亮当前选中节点,默认值是 false。 | boolean | — | false |
| default-expand-all | 是否默认展开所有节点 | boolean | — | false | | default-expand-all | 是否默认展开所有节点 | boolean | — | false |
| expand-on-click-node | 是否在点击节点的时候展开或者收缩节点, 默认值为 true如果为 false则只有点箭头图标的时候才会展开或者收缩节点。 | boolean | — | true | | expand-on-click-node | 是否在点击节点的时候展开或者收缩节点, 默认值为 true如果为 false则只有点箭头图标的时候才会展开或者收缩节点。 | boolean | — | true |

View File

@ -23,7 +23,6 @@
width: 890px; width: 890px;
height: 465px; height: 465px;
margin: 30px auto 100px; margin: 30px auto 100px;
/*border: solid 1px black;*/
position: relative; position: relative;
div { div {

View File

@ -25,14 +25,14 @@
"dist:all": "node build/bin/build-all.js && npm run build:theme", "dist:all": "node build/bin/build-all.js && npm run build:theme",
"i18n": "node build/bin/i18n.js", "i18n": "node build/bin/i18n.js",
"lint": "eslint src/**/* test/**/* packages/**/*.{js,vue} build/**/* --quiet", "lint": "eslint src/**/* test/**/* packages/**/*.{js,vue} build/**/* --quiet",
"pub": "npm run bootstrap && sh build/git-release.sh && sh build/release.sh && node build/bin/gen-indices.js", "pub": "npm run bootstrap && sh build/git-release.sh && sh build/release.sh && node build/bin/gen-indices.js && sh build/deploy-faas.sh",
"pub:all": "npm run dist:all && lerna publish --skip-git && git commit -am 'publish independent packages' && git push eleme dev", "pub:all": "npm run dist:all && lerna publish --skip-git && git commit -am 'publish independent packages' && git push eleme dev",
"test": "npm run lint && npm run build:theme && cross-env CI_ENV=/dev/ karma start test/unit/karma.conf.js --single-run", "test": "npm run lint && npm run build:theme && cross-env CI_ENV=/dev/ karma start test/unit/karma.conf.js --single-run",
"test:watch": "npm run build:theme && karma start test/unit/karma.conf.js" "test:watch": "npm run build:theme && karma start test/unit/karma.conf.js"
}, },
"faas": { "faas": {
"domain": "element", "domain": "element",
"public": "examples/element-ui" "public": "temp_web/element"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -51,7 +51,7 @@
:aria-selected="highlightedIndex === index" :aria-selected="highlightedIndex === index"
> >
<slot :item="item"> <slot :item="item">
{{ item[props.label] }} {{ item[valueKey] }}
</slot> </slot>
</li> </li>
</el-autocomplete-suggestions> </el-autocomplete-suggestions>
@ -82,14 +82,9 @@
directives: { Clickoutside }, directives: { Clickoutside },
props: { props: {
props: { valueKey: {
type: Object, type: String,
default() { default: 'value'
return {
label: 'value',
value: 'value'
};
}
}, },
popperClass: String, popperClass: String,
placeholder: String, placeholder: String,
@ -142,7 +137,8 @@
getMigratingConfig() { getMigratingConfig() {
return { return {
props: { props: {
'custom-item': 'custom-item is removed, use scoped slot intstead.' 'custom-item': 'custom-item is removed, use scoped slot instead.',
'props': 'props is removed, use value-key instead.'
} }
}; };
}, },
@ -199,7 +195,7 @@
} }
}, },
select(item) { select(item) {
this.$emit('input', item[this.props.label]); this.$emit('input', item[this.valueKey]);
this.$emit('select', item); this.$emit('select', item);
this.$nextTick(_ => { this.$nextTick(_ => {
this.suggestions = []; this.suggestions = [];

View File

@ -133,7 +133,7 @@ describe('Autocomplete', () => {
<el-autocomplete <el-autocomplete
v-model="state" v-model="state"
ref="autocomplete" ref="autocomplete"
:props="{ label: 'address', value: 'name' }" value-key="address"
:fetch-suggestions="querySearch" :fetch-suggestions="querySearch"
placeholder="请输入内容autocomplete2" placeholder="请输入内容autocomplete2"
></el-autocomplete> ></el-autocomplete>

View File

@ -34,14 +34,14 @@ export declare class ElAutocomplete extends ElementUIComponent {
/** Debounce delay when typing */ /** Debounce delay when typing */
debounce: number debounce: number
/** name for the inner native input */ /** Name for the inner native input */
name: string name: string
/** whether to emit select event on enter when there is no autocomplete match */ /** Key name of the input suggestion object for display */
selectWhenUnmatched: boolean valueKey: string
/** Component name of your customized suggestion list item */ /** Whether to emit select event on enter when there is no autocomplete match */
customItem: string selectWhenUnmatched: boolean
/** A method to fetch input suggestions. When suggestions are ready, invoke callback(data:[]) to return them to Autocomplete */ /** A method to fetch input suggestions. When suggestions are ready, invoke callback(data:[]) to return them to Autocomplete */
fetchSuggestions: FetchSuggestions fetchSuggestions: FetchSuggestions