Skip to content

Commit 9287981

Browse files
committed
feat: [Request] Data Table Inline Editing quasarframework#2023
1 parent 0766d2f commit 9287981

File tree

4 files changed

+174
-4
lines changed

4 files changed

+174
-4
lines changed

dev/components/components/data-table.vue

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,41 @@
1515
<q-radio v-model="separator" val="none" label="None" />
1616
</div>
1717

18+
<h2>Inline editing</h2>
19+
<p class="caption">Click on Dessert or Calories cells.</p>
20+
<q-table
21+
:data="data"
22+
:columns="columns"
23+
:filter="filter"
24+
:title="title"
25+
row-key="name"
26+
>
27+
<q-tr slot="body" slot-scope="props" :props="props">
28+
<q-td key="desc" :props="props">
29+
{{ props.row.name }}
30+
<q-inline-edit v-model="props.row.name">
31+
<q-field count>
32+
<q-input v-model="props.row.name" />
33+
</q-field>
34+
</q-inline-edit>
35+
</q-td>
36+
<q-td key="calories" :props="props">
37+
{{ props.row.calories }}
38+
<q-inline-edit v-model="props.row.calories" title="Update calories" buttons>
39+
<q-field count>
40+
<q-input type="number" v-model="props.row.calories" />
41+
</q-field>
42+
</q-inline-edit>
43+
</q-td>
44+
<q-td key="fat" :props="props">{{ props.row.fat }}</q-td>
45+
<q-td key="carbs" :props="props">{{ props.row.carbs }}</q-td>
46+
<q-td key="protein" :props="props">{{ props.row.protein }}</q-td>
47+
<q-td key="sodium" :props="props">{{ props.row.sodium }}</q-td>
48+
<q-td key="calcium" :props="props">{{ props.row.calcium }}</q-td>
49+
<q-td key="iron" :props="props">{{ props.row.iron }}</q-td>
50+
</q-tr>
51+
</q-table>
52+
1853
<h2>Grid style</h2>
1954
<q-table
2055
grid
@@ -255,11 +290,10 @@
255290
<q-tr slot="body" slot-scope="props" :props="props">
256291
<q-td key="desc" :props="props">
257292
{{ props.row.name }}
258-
<q-popover>
259-
<q-input hide-underline v-model="props.row.name" />
260-
</q-popover>
261293
</q-td>
262-
<q-td key="calories" :props="props">{{ props.row.calories }}</q-td>
294+
<q-td key="calories" :props="props">
295+
{{ props.row.calories }}
296+
</q-td>
263297
<q-td key="fat" :props="props">{{ props.row.fat }}</q-td>
264298
<q-td key="carbs" :props="props">{{ props.row.carbs }}</q-td>
265299
<q-td key="protein" :props="props">{{ props.row.protein }}</q-td>

src/components.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export * from './components/fab/index.js'
2020
export * from './components/field/index.js'
2121
export * from './components/icon/index.js'
2222
export * from './components/infinite-scroll/index.js'
23+
export * from './components/inline-edit/index.js'
2324
export * from './components/inner-loading/index.js'
2425
export * from './components/input/index.js'
2526
export * from './components/input-frame/index.js'
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import QPopover from '../popover/QPopover.js'
2+
import QBtn from '../btn/QBtn.js'
3+
import clone from '../../utils/clone.js'
4+
import { getEventKey } from '../../utils/event.js'
5+
6+
export default {
7+
name: 'QInlineEdit',
8+
props: {
9+
value: {},
10+
persistent: Boolean,
11+
title: String,
12+
buttons: Boolean,
13+
labelSet: String,
14+
labelCancel: String,
15+
color: {
16+
type: String,
17+
default: 'primary'
18+
},
19+
validate: {
20+
type: Function,
21+
default: () => true
22+
}
23+
},
24+
data () {
25+
return {
26+
initialValue: ''
27+
}
28+
},
29+
watch: {
30+
value () {
31+
this.$nextTick(() => {
32+
this.$refs.popover.reposition()
33+
})
34+
}
35+
},
36+
methods: {
37+
cancel () {
38+
if (this.__hasChanged()) {
39+
this.$emit('cancel', this.value, this.initialValue)
40+
this.$emit('input', this.initialValue)
41+
}
42+
this.$nextTick(this.__close)
43+
},
44+
set () {
45+
if (this.__hasChanged() && this.validate(this.value)) {
46+
this.$emit('save', this.value)
47+
}
48+
this.__close()
49+
},
50+
51+
__hasChanged () {
52+
return JSON.stringify(this.value) !== JSON.stringify(this.initialValue)
53+
},
54+
__close () {
55+
this.validated = true
56+
this.$refs.popover.hide()
57+
},
58+
__getContent (h) {
59+
const title = this.$slots.title || this.title
60+
return [
61+
(title && h('div', { staticClass: 'q-title q-mt-sm q-mb-sm' }, [ title ])) || void 0
62+
].concat(this.$slots.default).concat([
63+
(this.buttons && h('div', { staticClass: 'row justify-center no-wrap q-mt-sm' }, [
64+
h(QBtn, {
65+
props: {
66+
flat: true,
67+
color: this.color,
68+
label: this.labelCancel || this.$q.i18n.label.cancel
69+
},
70+
on: {
71+
click: this.cancel
72+
}
73+
}),
74+
h(QBtn, {
75+
staticClass: 'q-ml-sm',
76+
props: {
77+
flat: true,
78+
color: this.color,
79+
label: this.labelSet || this.$q.i18n.label.set
80+
},
81+
on: {
82+
click: this.set
83+
}
84+
})
85+
])) || void 0
86+
])
87+
}
88+
},
89+
render (h) {
90+
return h(QPopover, {
91+
staticClass: 'q-table-edit q-px-md q-py-sm',
92+
ref: 'popover',
93+
props: {
94+
cover: true,
95+
persistent: this.persistent
96+
},
97+
on: {
98+
show: () => {
99+
const input = this.$el.querySelector('input')
100+
input && input.focus()
101+
this.$emit('show')
102+
this.initialValue = clone(this.value)
103+
this.validated = false
104+
},
105+
hide: () => {
106+
if (this.validated) { return }
107+
108+
if (this.__hasChanged()) {
109+
if (this.validate(this.value)) {
110+
this.$emit('save', this.value)
111+
}
112+
else {
113+
this.$emit('cancel', this.value, this.initialValue)
114+
this.$emit('input', this.initialValue)
115+
}
116+
}
117+
118+
this.$emit('hide')
119+
}
120+
},
121+
nativeOn: {
122+
keydown: e => {
123+
if (getEventKey(e) === 13) {
124+
this.$refs.popover.hide()
125+
}
126+
}
127+
}
128+
}, this.__getContent(h))
129+
}
130+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import QInlineEdit from './QInlineEdit.js'
2+
3+
export {
4+
QInlineEdit
5+
}

0 commit comments

Comments
 (0)