Vue - обновление данных в пользовательском компоненте таблицы начальной загрузки - PullRequest
0 голосов
/ 28 ноября 2018

Я пытаюсь создать пользовательский компонент в 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>
            &emsp;
            <b-button @click.prevent="resetData" size="md" variant="outline-danger">Reset</b-button>
        </div>
    </footer>
</div>

1 Ответ

0 голосов
/ 01 декабря 2018

Я попытался воспроизвести вашу проблему на простом примере (см .: 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);
    }
  }

При монтировании я выполняю функцию, которая делает копию данных. Это делается с помощью среза, потому что в противном случае он делает только ссылкук исходному массиву (обратите внимание, что обычно JS передается по значению, но, как указано в документации vue с объектами, и, следовательно, внутри vue, он передается по ссылке (см .: Документы Vue , прокрутите дотекст, помеченный красным)).

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

Теперь вы можете просто удалить запись, а также сбросить все данные.

ПОСМОТРЕТЬ ПОЛНУЮ ДЕМО

Я надеюсь, что это решит вашу проблему, и если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.

...