4 |
<template>
117 | <VueQuintable :table-classes="tableClasses" :config="config" :rows="rows" @component:event="componentListener">
118 |
119 | <template v-slot:header>
120 | <div class="row">
121 | <div class="col-md-2">
122 | <div class="mb-3">
123 | <label for="index" >Index</label>
124 | <v-select id="index" :options="indexes" v-model="index" :clearable="false"></v-select>
125 | </div>
126 | </div>
127 | <div class="col-md-2">
128 | <div class="mb-3">
129 | <label for="name" >Name</label>
130 | <input id="name" v-model="name" type="text" class="form-control">
131 | </div>
132 | </div>
133 | <div class="col-md-2">
134 | <div class="mb-3">
135 | <label for="age" >Age</label>
136 | <v-select id="age" :options="ages" v-model="age" placeholder="Select Age..."></v-select>
137 | </div>
138 | </div>
139 | <div class="col-md-2">
140 | <div class="mb-3">
141 | <label for="city" >City</label>
142 | <input id="city" v-model="city" type="text" class="form-control">
143 | </div>
144 | </div>
145 | <div class="col-md-2">
146 | <div class="mb-3">
147 | <label for="job" >Job</label>
148 | <input id="job" v-model="job" type="text" class="form-control">
149 | </div>
150 | </div>
151 | <div class="col-md-2">
152 | <label><wbr></label>
153 | <div class="mb-3">
154 | <span class="btn btn-info" @click="addRow"><font-awesome-icon icon="plus"></font-awesome-icon> Add Row</span>
155 | </div>
156 | </div>
157 | </div>
158 | </template>
159 |
160 | </VueQuintable>
161 | </template>
162 | <script>
163 | import VueQuintable from "../components/VueQuintable.vue"
164 | import DragComponent from "./components/DragComponent.vue"
165 | import ActionsComponent from "./components/ActionsComponent.vue"
166 | import Vue from "vue"
167 |
168 |
169 | Vue.component(
170 | "actions-component",
171 | ActionsComponent.default || ActionsComponent
172 | );
173 |
174 | Vue.component(
175 | "drag-component",
176 | DragComponent.default || DragComponent
177 | );
178 |
179 | import Chance from "chance";
180 |
181 | export default {
182 | components:{
183 | VueQuintable
184 | },
185 | data() {
186 | return {
187 | config: {
188 | columns: [
189 | {
190 | headline: "",
191 | },{
192 | headline: "Name",
193 | }, {
194 | headline: "Age",
195 | breakpoint:"md",
196 | }, {
197 | headline: "Birth Place",
198 | breakpoint:"lg",
199 | }, {
200 | headline: "Job",
201 | breakpoint:"lg",
202 | },{
203 | headline:"Actions",
204 | breakpoint:"sm",
205 | }
206 | ],
207 | },
208 | rows:[],
209 | index:1,
210 | name:"",
211 | age:null,
212 | city:"",
213 | job:"",
214 | rowCount:10,
215 | dragging:false,
216 | }
217 |
218 | },
219 | computed:{
220 | tableClasses() {
221 | return this.dragging ? "dragging" : "";
222 | },
223 |
224 | ages() {
225 | return Array.range(1, 99);
226 | },
227 |
228 | indexes(){
229 | return this.rows.map((row,index)=>{
230 | return index+1;
231 | });
232 | }
233 | },
234 | created(){
235 |
236 | Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
237 |
238 | const rows = [];
239 |
240 | const chance = new Chance();
241 |
242 | for(let i = 0; i < this.rowCount; i++){
243 | rows.push([
244 | {
245 | component:{
246 | name:"drag-component",
247 | props:{
248 | index:i,
249 | },
250 |
251 | }
252 | },
253 | {
254 | text:chance.name({ nationality: 'en' })
255 | },
256 | {
257 | text:chance.age()
258 | },
259 | {
260 | text:chance.city()
261 | },
262 | {
263 | text:chance.profession()
264 | },
265 | {
266 | component:{
267 | name:"actions-component",
268 | props:{
269 | index:i,
270 | first:i===0,
271 | last:i===this.rowCount -1,
272 | },
273 |
274 | }
275 | }
276 | ]);
277 | }
278 |
279 | this.rows = rows;
280 | },
281 | methods:{
282 |
283 | updateIndexes(){
284 | this.rows = this.rows.map((row,index)=>{
285 | row[5].component.props.index = index;
286 | row[5].component.props.first = index === 0;
287 | row[5].component.props.last = index === this.rowCount - 1;
288 | row[0].component.props.index = index;
289 | return row;
290 | });
291 | },
292 |
293 | componentListener(data){
294 | if(data.type === "delete-row"){
295 | this.rows.splice(data.index,1);
296 | this.rowCount--;
297 | this.updateIndexes();
298 | }else if(data.type === "move-row"){
299 | this.move(data.index,data.to);
300 | }else if(data.type === "dragstart"){
301 | this.dragging = true;
302 | }else if(data.type === "dragend"){
303 | this.dragging = false;
304 | }
305 | },
306 |
307 | move(old_index, new_index) {
308 | if (new_index >= this.rows.length) {
309 | var k = new_index - this.rows.length + 1;
310 | while (k--) {
311 | this.rows.push(undefined);
312 | }
313 | }
314 | this.rows.splice(new_index, 0, this.rows.splice(old_index, 1)[0]);
315 | this.updateIndexes();
316 |
317 | },
318 | addRow(){
319 |
320 | if(!this.name || !this.age || !this.city || !this.job){
321 | alert("You have to fill out all inputs");
322 | return;
323 | }
324 |
325 | const data = [
326 | {
327 | component:{
328 | name:"drag-component",
329 | props:{
330 | index:this.index - 1,
331 | },
332 |
333 | }
334 | },
335 | {
336 | text:this.name
337 | },
338 | {
339 | text:this.age
340 | },
341 | {
342 | text:this.city
343 | },
344 | {
345 | text:this.job
346 | },
347 | {
348 | component:{
349 | name:"actions-component",
350 | props:{
351 | index:this.index - 1,
352 | },
353 |
354 | }
355 | }
356 | ];
357 |
358 | if(this.index === this.rowCount){
359 | this.rows.push(data);
360 | }else{
361 | this.rows.splice(this.index - 1 , 0, data);
362 | }
363 |
364 | this.index = 1;
365 | this.name = "";
366 | this.age = null;
367 | this.city = "";
368 | this.job = "";
369 | this.rowCount ++;
370 |
371 | this.updateIndexes();
372 |
373 | }
374 | }
375 | }
376 | </script>
377 |
378 | <style>
379 | .vue-quintable.dragging .vue-quintable-cell{
380 | position: relative;
381 | }
382 |
383 | .vue-quintable.dragging .vue-quintable-cell:after{
384 | content: "";
385 | position: absolute;
386 | width: 100%;
387 | height: 100%;
388 | background-color: rgba(255,255,255,0.75);
389 | left: 0;
390 | top: 0;
391 | pointer-events: none;
392 | z-index: 2;
393 | }
394 |
395 | .vue-quintable.dragging .vue-quintable-cell.actions .drop-element{
396 | position: relative;
397 | z-index: 3;
398 |
399 | }
400 |
401 | .vue-quintable.dragging .vue-quintable-cell.actions .drop-element .card{
402 | background-color: #28a745;
403 | color: #fff;
404 | }
405 |
406 | </style>
407 | <template>
414 | <div class="content">
415 | <div class="btn-group me-2">
416 | <div class="btn btn-info" :disabled="first" :class="{disabled:first}" @click="moveRow('up')">
417 | <font-awesome-icon icon="chevron-up"></font-awesome-icon>
418 | </div>
419 | <div class="btn btn-info" :disabled="last" :class="{disabled:last}" @click="moveRow('down')">
420 | <font-awesome-icon icon="chevron-down"></font-awesome-icon>
421 | </div>
422 | </div>
423 | <div class="btn btn-danger me-2" @click="deleteRow" title="Delete Row">
424 | <font-awesome-icon icon="times"></font-awesome-icon>
425 | </div>
426 |
427 | <drop class="d-inline-block align-middle drop-element" @drop="handleDrop" title="Drop your dragging row here to move it">
428 | <div class="card px-3 d-inline-block">
429 | <div class="py-2 bg-muted">
430 | <font-awesome-icon icon="expand"></font-awesome-icon>
431 | </div>
432 | </div>
433 | </drop>
434 | </div>
435 | </template>
436 |
437 |
438 | <script>
439 | import { Drop } from 'vue-drag-drop';
440 |
441 | export default {
442 | props:{
443 | first:{
444 | type:Boolean,
445 | default:false
446 | },
447 | last:{
448 | type:Boolean,
449 | default:false
450 | },
451 | index:{
452 | type:Number
453 | }
454 | },
455 | components:{
456 | Drop
457 | },
458 | data(){
459 | return {
460 | checked:false,
461 | reference:"checkbox-component",
462 | }
463 | },
464 | methods: {
465 | handleDrop(data) {
466 | this.$emit("action",
467 | {
468 | index:data.index,
469 | type:"move-row",
470 | to:this.index
471 | }
472 | )
473 | },
474 | moveRow(mode = "up") {
475 |
476 | if(mode === "up" && this.first || mode === "down" && this.last){
477 | return;
478 | }
479 |
480 | this.$emit("action",
481 | {
482 | index:this.index,
483 | type:"move-row",
484 | to:mode === "up" ? this.index - 1:this.index + 1
485 | }
486 | )
487 | },
488 | deleteRow(){
489 | this.$emit("action",
490 | {
491 | index:this.index,
492 | type:"delete-row",
493 | }
494 | )
495 | }
496 | }
497 | }
498 |
499 | </script>
500 | <style scoped>
501 | .btn.disabled{
502 | cursor: not-allowed;
503 | }
504 | </style>
505 |
506 |
507 |
508 | <template>
514 | <drag class="d-inline-block" :transfer-data="{ index: index }" :effect-allowed="['move']"
515 | drop-effect="move" @dragend="dragend" @dragstart="dragstart">
516 | <div class="btn p-2">
517 | <font-awesome-icon icon="arrows-alt"></font-awesome-icon>
518 | </div>
519 | </drag>
520 | </template>
521 | <script>
522 | import { Drag } from 'vue-drag-drop';
523 |
524 | export default {
525 | props:{
526 | index:{
527 | type:Number
528 | }
529 | },
530 | components:{
531 | Drag
532 | },
533 | methods:{
534 | dragstart(){
535 | this.$emit("action",
536 | {
537 | index:this.index,
538 | type:"dragstart",
539 | }
540 | );
541 | },
542 | dragend(){
543 | this.$emit("action",
544 | {
545 | index:this.index,
546 | type:"dragend",
547 | }
548 | );
549 | }
550 | }
551 | }
552 | </script>
553 |
554 |
555 |