Vue-更新Bootstrap表自定义组件上的数据

时间:2018-11-28 17:52:55

标签: vue.js vuejs2 vue-component bootstrap-vue

我正在尝试在Vue 2.0中制作一个自定义组件,以扩展Bootstrap Vue库<b-table>的现有功能。除了在index.jsp中定义的removeRow和resetData函数无法按我希望的方式工作外,它基本上可以按我的意愿进行工作。

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>
            &emsp;
            <b-button @click.prevent="resetData" size="md" variant="outline-danger">Reset</b-button>
        </div>
    </footer>
</div>

1 个答案:

答案 0 :(得分:3)

我尝试通过一个简单的示例来重现您的问题(请参阅:https://codesandbox.io/s/m30wqm0xk8?module=%2Fsrc%2Fcomponents%2FGridTest.vue),并且遇到了您遇到的相同问题。就像其他人已经说过的一样,我同意重置原始数据的最简单方法是进行复制。我写了两种删除和重置数据的方法。

methods: {
    removeRow(id) {
      const index = this.records.findIndex(item => item.index === id);

      this.records.splice(index, 1);
    },
    resetData() {
      this.records = this.copyOfOrigin.slice(0);
    }
  }

在挂载时,我执行一个复制数据的函数。这是通过slice来完成的,因为否则它将仅对原始数组进行引用(请注意,通常JS是按值传递,但是如vue文档中的对象所述,因此在vue内部它是按引用传递的(请参见:Vue docs滚动到红色标记的文本)。

mounted: function() {
    this.copyOfOrigin = this.records.slice(0);
  } 

现在,您可以简单地删除记录,但也可以重置所有数据。

SEE FULL DEMO

我希望这可以解决您的问题,如果您有任何疑问,请随时提问。