Я пытаюсь создать пользовательский компонент в Vue 2.0, который расширяет существующие функции библиотеки Bootstrap Vue <b-table>
.В основном это работает так, как мне хотелось бы, за исключением того, что функции removeRow и resetData, определенные в index.jsp, не работают так, как мне бы хотелось.
removeRow визуально удаляет строку и удаляет ее из реквизита data
, но строка появляется снова после следующего взаимодействия (сортировка, фильтрация и т. Д.).Так что это на самом деле не обновляет правильную вещь.Я пытаюсь использовать v-модель в качестве поверхностной копии элементов, чтобы можно было удалить ее, не затрагивая исходный набор данных, но я просто что-то упустил.
resetData действительно устанавливает данныев таблице обратно правильно, но не выполняет повторную визуализацию таблицы, поэтому вы не можете видеть повторно добавленные строки, пока не выполните отдельное взаимодействие (сортировка, фильтр и т. д.), и в этом случае они появляются снова.
Так что я знаю, что я немного близок, но был бы очень признателен за понимание того, как это работает правильно и как я могу улучшить любую часть этого компонента.
OreillyTable.vue.js
const OreillyTable = {
inheritAttrs: false,
data: function () {
return {
filter: null,
sortDesc: false,
hideEmpty: false,
isBusy: false,
currentPage: 1,
data: null
}
},
mounted: function () {
let filtered = this.slots.filter(function(value, index, arr){
return value.customRender;
});
this.slots = filtered;
},
methods: {
oreillyTableSort (a, b, key) {
if (a[key] === null || b[key] === null) {
return a[key] === null && b[key] !== null ? -1 : (a[key] !== null && b[key] === null ? 1 : 0);
} else if (typeof a[key] === 'number' && typeof b[key] === 'number') {
// If both compared fields are native numbers
return a[key] < b[key] ? -1 : (a[key] > b[key] ? 1 : 0)
} else {
// Stringify the field data and use String.localeCompare
return this.toString(a[key]).localeCompare(this.toString(b[key]), undefined, {
numeric: true
});
}
},
toString (val) {
return typeof val !== "undefined" && val != null ? val.toString() : '';
},
oreillyFilter (filteredItems) {
this.totalRows = filteredItems.length;
this.currentPage = 1;
}
},
props: {
fields: {
type: Array
},
items: {
type: Array,
required: true
},
hideEmpty: {
type: Boolean
},
filterPlaceholder: {
type: String,
default: "Filter"
},
sortFunction: {
type: Function,
default: null
},
filterFunction: {
type: Function,
default: null
},
slots: {
type: Array
},
sortBy: {
type: String,
default: null
},
perPage: {
type: Number,
default: 10
},
value: {
}
},
template: `<div :class="{ 'no-events' : isBusy }">
<b-row>
<b-col md="12">
<b-form-group class="mb-2 col-md-3 float-right pr-0">
<b-input-group>
<b-form-input v-model="filter" :placeholder="filterPlaceholder" class="form-control" />
</b-input-group>
</b-form-group>
</b-col>
</b-row>
<div class="position-relative">
<div v-if="isBusy" class="loader"></div>
<b-table stacked="md" outlined responsive striped hover
v-bind="$attrs"
v-model="data"
:show-empty="!hideEmpty"
:items="items"
:fields="fields"
:no-provider-sorting="true"
:no-sort-reset="true"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:sort-compare="sortFunction === null ? this.oreillyTableSort : sortFunction"
:busy.sync="isBusy"
:current-page="currentPage"
:per-page="perPage"
@filtered="filterFunction === null ? this.oreillyFilter : filterFunction">
<template :slot="slot.key" slot-scope="row" v-for="slot in slots">
<slot :name="slot.key" :data="row"></slot>
</template>
</b-table>
<b-row v-if="items.length > perPage">
<b-col sm="12">
<b-pagination size="md" :total-rows="items.length" v-model="currentPage" :per-page="perPage"></b-pagination>
</b-col>
</b-row>
</div>
</div>`
};
index.jsp
<script>
Vue.use(window.vuelidate.default);
Vue.component('oreilly-table', OreillyTable);
const dashboardItems = [
{ id: 12, firstName: "John", lastName: "Adams", tmNumber: "588999", team: "Corporate", flapjackCount: 4, enrollDate: "2018-11-05" },
{ id: 13, firstName: "George", lastName: "Washington", tmNumber: "422111", team: "America", flapjackCount: 28, enrollDate: "2018-10-01" },
{ id: 14, firstName: "Abraham", lastName: "Lincoln", tmNumber: "358789", team: "America", flapjackCount: 16, enrollDate: "2017-09-02" },
{ id: 15, firstName: "Jimmy", lastName: "Carter", tmNumber: "225763", team: "Core", flapjackCount: 9, enrollDate: "2018-03-02" },
{ id: 16, firstName: "Thomas", lastName: "Jefferson", tmNumber: "169796", team: "Core", flapjackCount: 14, enrollDate: "2018-05-01" }
];
const Dashboard = {
template: `<jsp:include page="dashboard.jsp"/>`,
data: function(){
return {
notification: {
text: "The Great Flapjack Contest will be held on December 25, 2018.",
variant: "primary",
timer: true
},
fields: [
{ key: "name", label: "Name", sortable: true, customRender: true },
{ key: "team", label: "Team", sortable: true },
{ key: "enrollDate", label: "Enrollment Date", sortable: true, formatter: (value) => {return new Date(value).toLocaleDateString();} },
{ key: "flapjackCount", sortable: true },
{ key: "id", label: "", 'class': 'text-center', customRender: true }
]
}
},
methods: {
removeRow: function(id) {
this.$refs.table.isBusy = true;
setTimeout(() => { console.log("Ajax Request Here"); this.$refs.table.isBusy = false; }, 1000);
const index = this.$refs.table.data.findIndex(item => item.id === id)
if (~index)
this.$refs.table.data.splice(index, 1)
},
resetData: function() {
this.$refs.table.data = dashboardItems;
}
}
};
const router = new VueRouter({
mode: 'history',
base: "/ProjectTemplate/flapjack",
routes: [
{ path: '/enroll', component: Enroll },
{ path: '/', component: Dashboard },
{ path: '/404', component: NotFound },
{ path: '*', redirect: '/404' }
]
});
new Vue({router}).$mount('#app');
dashboard.jsp
<compress:html>
<div>
<oreilly-table ref="table" :items="dashboardItems" :slots="fields" :fields="fields">
<template slot="name" slot-scope="row">
{{ row.data.item.firstName }} {{ row.data.item.lastName }} ({{ row.data.item.tmNumber }})
</template>
<template slot="id" slot-scope="row">
<a href="#" @click.prevent="removeRow(row.data.item.id)">Remove</a>
</template>
</oreilly-table>
<footer class="footer position-sticky fixed-bottom bg-light">
<div class="container text-center">
<router-link tag="button" class="btn btn-outline-secondary" id="button" to="/enroll">Enroll</router-link>
 
<b-button @click.prevent="resetData" size="md" variant="outline-danger">Reset</b-button>
</div>
</footer>
</div>