Skip to content

Commit 38cd459

Browse files
Merge pull request SortableJS#660 from SortableJS/correct_functional_bug
Correct functional bug
2 parents f438b91 + 1c4958c commit 38cd459

File tree

6 files changed

+170
-15
lines changed

6 files changed

+170
-15
lines changed

example/components/functional.vue

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<template>
2+
<div class="row">
3+
<div class="col-8">
4+
<h3>Draggable</h3>
5+
<draggable
6+
v-model="rows"
7+
tag="v-layout"
8+
class="row wrap fill-height align-center sortable-list"
9+
style="background: grey;"
10+
>
11+
<v-flex
12+
v-for="row in rows"
13+
:key="row.index"
14+
class="sortable"
15+
xs12
16+
my-2
17+
style="background: red"
18+
>
19+
<draggable
20+
:list="row.items"
21+
tag="v-layout"
22+
:group="{ name: 'row' }"
23+
class="row wrap justify-space-around"
24+
>
25+
<v-flex
26+
v-for="item in row.items"
27+
:key="item.title"
28+
xs4
29+
pa-3
30+
class="row-v"
31+
>
32+
<v-card style="height: 100px;">{{ item.title }}</v-card>
33+
</v-flex>
34+
</draggable>
35+
</v-flex>
36+
</draggable>
37+
</div>
38+
39+
<rawDisplayer
40+
class="col-3"
41+
:value="rows"
42+
title="List"
43+
/>
44+
</div>
45+
</template>
46+
47+
<script>
48+
import draggable from "@/vuedraggable";
49+
import Vue from "vue";
50+
import Vuetify from "vuetify";
51+
import "vuetify/dist/vuetify.min.css";
52+
53+
Vue.use(Vuetify);
54+
55+
export default {
56+
name: "functional",
57+
display: "Functional third party",
58+
order: 17,
59+
components: {
60+
draggable
61+
},
62+
data() {
63+
return {
64+
enabled: true,
65+
rows: [
66+
{
67+
index: 1,
68+
items: [
69+
{
70+
title: "item 1"
71+
}
72+
]
73+
},
74+
{
75+
index: 2,
76+
items: [
77+
{
78+
title: "item 2"
79+
},
80+
{
81+
title: "item 3"
82+
}
83+
]
84+
}
85+
]
86+
};
87+
}
88+
};
89+
</script>
90+
<style scoped>
91+
.buttons {
92+
margin-top: 35px;
93+
}
94+
95+
.row-v {
96+
height: 150px;
97+
width: 200px;
98+
}
99+
100+
.ghost {
101+
opacity: 0.5;
102+
background: #c8ebfb;
103+
}
104+
</style>

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"vue-router": "^3.0.2",
5252
"vue-server-renderer": "^2.6.8",
5353
"vue-template-compiler": "^2.6.8",
54+
"vuetify": "^1.5.16",
5455
"vuex": "^3.1.1"
5556
},
5657
"eslintConfig": {

src/vuedraggable.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ const draggableComponent = {
146146
data() {
147147
return {
148148
transitionMode: false,
149-
noneFunctionalComponentMode: false,
150-
init: false
149+
noneFunctionalComponentMode: false
151150
};
152151
},
153152

@@ -186,7 +185,8 @@ const draggableComponent = {
186185

187186
mounted() {
188187
this.noneFunctionalComponentMode =
189-
this.getTag().toLowerCase() !== this.$el.nodeName.toLowerCase();
188+
this.getTag().toLowerCase() !== this.$el.nodeName.toLowerCase() &&
189+
!this.getIsFunctional();
190190
if (this.noneFunctionalComponentMode && this.transitionMode) {
191191
throw new Error(
192192
`Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.getTag()}`
@@ -251,6 +251,11 @@ const draggableComponent = {
251251
},
252252

253253
methods: {
254+
getIsFunctional() {
255+
const { fnOptions } = this._vnode;
256+
return fnOptions && fnOptions.functional;
257+
},
258+
254259
getTag() {
255260
return this.tag || this.element;
256261
},
@@ -265,12 +270,6 @@ const draggableComponent = {
265270
},
266271

267272
getChildrenNodes() {
268-
if (!this.init) {
269-
this.noneFunctionalComponentMode =
270-
this.noneFunctionalComponentMode && this.$children.length === 1;
271-
this.init = true;
272-
}
273-
274273
if (this.noneFunctionalComponentMode) {
275274
return this.$children[0].$slots.default;
276275
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export default {
2+
name: "FakeFunctional",
3+
functional:true,
4+
props: {
5+
prop1: {
6+
type: String,
7+
default: "string"
8+
}
9+
},
10+
render(createElement, context) {
11+
return createElement('button', 'Click me');
12+
}
13+
}

tests/unit/vuedraggable.spec.js

+38-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Sortable.mockImplementation(() => SortableFake);
1010
import draggable from "@/vuedraggable";
1111
import Vue from "vue";
1212
import Fake from "./helper/FakeComponent.js"
13+
import FakeFunctional from "./helper/FakeFunctionalComponent.js"
14+
1315

1416
let wrapper;
1517
let vm;
@@ -190,18 +192,28 @@ describe("draggable.vue when initialized with list", () => {
190192
expect(wrapper.html()).toEqual(initialRender);
191193
})
192194

193-
test.each([
195+
describe.each([
194196
"ul",
195197
"span",
196198
"div"
197199
])(
198-
"renders tag %s as root element",
200+
"considering a tag %s",
199201
(tag) => {
200-
wrapper = shallowMount(draggable, {
201-
propsData: { tag }
202+
beforeEach(() => {
203+
wrapper = shallowMount(draggable, {
204+
propsData: { tag }
205+
});
202206
});
203-
const expectedRegex = new RegExp(`^<${tag}>.*<\/${tag}>$`);
204-
expect(wrapper.html()).toMatch(expectedRegex);
207+
208+
it("renders tag as root element", () => {
209+
const expectedRegex = new RegExp(`^<${tag}>.*<\/${tag}>$`);
210+
expect(wrapper.html()).toMatch(expectedRegex);
211+
})
212+
213+
it("set noneFunctionalComponentMode to false ", () => {
214+
const { noneFunctionalComponentMode } = vm;
215+
expect(noneFunctionalComponentMode).toBe(false);
216+
})
205217
}
206218
)
207219

@@ -271,6 +283,26 @@ describe("draggable.vue when initialized with list", () => {
271283
})
272284
});
273285

286+
test.each([
287+
[Fake, true],
288+
[FakeFunctional, false]
289+
])(
290+
"when using component as tag",
291+
(component, expectedNoneFunctionalComponentMode) => {
292+
wrapper = mount(draggable, {
293+
propsData: {
294+
tag: "child",
295+
},
296+
stubs: {
297+
child: component
298+
}
299+
});
300+
const { vm: { noneFunctionalComponentMode } } = wrapper;
301+
expect(noneFunctionalComponentMode).toBe(expectedNoneFunctionalComponentMode);
302+
}
303+
)
304+
305+
274306
it("keeps a reference to Sortable instance", () => {
275307
expect(vm._sortable).toBe(SortableFake);
276308
})

0 commit comments

Comments
 (0)