【问题标题】:sortable and filterable not work in dynamic data from api in DataTable vuetify可排序和可过滤在 DataTable vuetify 中来自 api 的动态数据中不起作用
【发布时间】:2021-03-24 02:58:34
【问题描述】:

可排序和可过滤不适用于 DataTable vuetify 中 API 的动态数据

它适用于静态数据。

在 laravel api 中:

 $posts = Post::select('id', 'title', 'type', 'active', 'category_id')
                    ->with('category')
                    ->where('author_id', $request['userId'])
                    ->orderBy('created_at', 'desc')
                    ->paginate($size);

在客户端:

        <template>
          <main>
            <v-app>
              <!--breadcrumbs-->
              <breadcrumbs :breadcrumbs="breadcrumbs"></breadcrumbs>
              <!---->
              <!--actions-->
              <div class="actions container">
                <v-btn class="action__button" depressed color="success" @click="gotoNewCategory">
                  <v-icon dark> mdi-plus </v-icon>
                  insert category
                </v-btn>
              </div>
              <!---->
<v-card style="margin: 15px; padding: 10px">
        <v-text-field
          v-model="search"
          append-icon="mdi-magnify"
          label="search"
          single-line
          hide-details
        ></v-text-field>
      </v-card>

              <!--datatable-->
              <v-data-table
                :headers="headers"
                :items="categorys"
                :page="page"
                :pageCount="numberOfPages"
                :options.sync="options"
                :server-items-length="totalCategorys"
                :loading="loading"
:search="search"
                class="elevation-1"
                no-data-text="no data!"
                :footer-props="{
                  showFirstLastPage: true,
                  'items-per-page-text': 'test',
                  'items-per-page-all-text': 'all',
                  'page-text': '',
                }"
              >
                <template v-slot:top>
                  <v-dialog v-model="dialogDelete" max-width="500px">
                    <v-card>
                      <v-card-title class="headline">
    </v-card-title
                      >
                      <v-card-actions>
                        <v-spacer></v-spacer>
                        <v-btn color="blue darken-1" text @click="closeDelete">no</v-btn>
                        <v-btn color="blue darken-1" text @click="deleteCategoryConfirm"
                          >yes</v-btn
                        >
                        <v-spacer></v-spacer>
                      </v-card-actions>
                    </v-card>
                  </v-dialog>
                </template>
                <template v-slot:[`item.actions`]="{ item }">
                  <td>
                    <v-icon small class="mr-2" @click="editCategory(item)"> mdi-pencil </v-icon>
        
                    <v-icon small @click="deleteCategory(item)"> mdi-delete </v-icon>
                  </td>
                </template>
              </v-data-table>
              <!---->
            </v-app>
          </main>
        </template>
        <script>
        import breadcrumbs from "~/components/breadcrumbs";
        
        export default {
          name: "categorys",
          layout: "dashboard",
          components: { breadcrumbs },
        
          data() {
            return {
search: "",
              page: 1,
              totalCategorys: 0,
              numberOfPages: 0,
              dialogDelete: false,
              editedIndex: -1,
              categoryIdForDelete: "",
              loading: true,
              options: {},
              headers: [
                { text: "ID", value: "id", align: "start" },
                { text: "categoryName", value: "categoryName", align: "start" },
                { text: "actions", value: "actions", sortable: false },
              ],
              categorys: [],
              
            };
          },
          //this one will populate new data set when user changes current page.
          watch: {
            options: {
              handler() {
                this.readDataFromAPI();
              },
            },
            deep: true,
          },
          methods: {
            readDataFromAPI() {
              this.loading = true;
              const { page, itemsPerPage, sortBy, sortDesc } = this.options;
              let pageNumber = page;
        
              this.$axios
                .get(
                  "/api/category/categories?size=" +
                    itemsPerPage +
                    "&page=" +
                    pageNumber +
                    "&sortby=" +
                    sortBy +
                    "&sortDesc=" +
                    sortDesc,
                  this.fields
                )
                .then((response) => {
                  this.loading = false;
                  this.categorys = response.data.result.data;
                  this.totalCategorys = response.data.result.total;
                  this.numberOfPages = Math.round(response.data.result.total / itemsPerPage);
                });
            },
            filterOnlyCapsText(value, search, item) {
              return (
                value != null &&
                search != null &&
                typeof value === "string" &&
                value.toString().toLocaleUpperCase().indexOf(search) !== -1
              );
            },
            gotoNewCategory() {
              this.$router.push("/dashboard/categorys/new");
            },
            editCategory(item) {
              this.$router.push({ name: "dashboard-categorys-edit", params: item });
            },
            deleteCategory(category) {
              this.categoryIdForDelete = category.id;
              this.editedIndex = this.categorys.indexOf(category);
              this.dialogDelete = true;
            },
        
            deleteCategoryConfirm() {
              this.categorys.splice(this.editedIndex, 1);
              this.$axios
                .delete("api/category/delete?id=" + this.categoryIdForDelete)
                .then((response) => {
                  if (response.data.status === "success") {
                    this.$toast.show(response.data.message, {
                      theme: "toasted-primary",
                      position: "bottom-left",
                      type: "success",
                      duration: 2000,
                    });
                  } else {
                    let list = [];
                    $.each(response.data.message, function (key, value) {
                      list.push(value);
                    });
                    this.$toast.show(list, {
                      theme: "toasted-primary",
                      position: "bottom-left",
                      type: "error",
                      duration: 4000,
                    });
                  }
                });
              this.closeDelete();
            },
        
            closeDelete() {
              this.dialogDelete = false;
              this.$nextTick(() => {
                this.editedIndex = -1;
              });
            },
          },
          mounted() {
            this.readDataFromAPI();
          },
          filters: {
            striphtmltag: function (value) {
              var div = document.createElement("div");
              div.innerHTML = value;
              var text = div.textContent || div.innerText || "";
              return text;
            },
          },
        };
        </script>
        <style lang="scss" scoped>
        * {
          font-family: YekanBakh !important;
          letter-spacing: normal !important;
        }
        
        button {
          &:focus {
            outline: none !important;
          }
        }
        
        .elevation-1 {
          box-shadow: 0 0.46875rem 2.1875rem rgba(4, 9, 20, 0.03),
            0 0.9375rem 1.40625rem rgba(4, 9, 20, 0.03), 0 0.25rem 0.53125rem rgba(4, 9, 20, 0.05),
            0 0.125rem 0.1875rem rgba(4, 9, 20, 0.03) !important;
          margin: 15px;
        }
        </style>

filterable 不能传递给 API 变量。

但在可排序选项中:

groupBy: 数组(0) groupDesc:数组(0) 每页项目数:10 多重排序:假 必须排序:假 页数:1 排序依据:数组(0) sortDesc: 数组(0)

【问题讨论】:

  • 你是如何在 vue 组件中获取数据的。请分享代码。
  • 可排序好的。 orderBy == 变量...但可过滤不起作用
  • 如果您共享后端 api 代码,并希望在前端提供帮助.. 没有人可以帮助您:) 您需要共享组件代码..
  • 你没有分享你是如何使用 vuetify 数据表的
  • 添加所有代码。请检查。

标签: javascript vue.js nuxt.js vuetify.js


【解决方案1】:

这里的问题是您使用的是 server-items-length。对于 Vuetify,这意味着您将负责源/后端中的数据过滤和排序(API 调用响应数据将返回过滤和排序的结果)

正如Vuetify Data Table documentation 中提到的,在使用server-items-length时,您必须实现自己的过滤和排序逻辑。

您可以这样做

  1. 更新您的 readDataFromAPI 方法,在 API 的请求参数中包含“搜索”数据属性。

  2. 您可以为数据属性“search”添加另一个观察程序,并在其中调用方法 readDataFromAPI (我不喜欢这种实现,因为它会使用每个字符调用后端,这将是一项昂贵的操作。仍然取决于您的用例)

search(val) {
    this.readDataFromAPI()
},

更好的实现方式是在搜索文本字段的附加图标中添加一个事件侦听器,以调用 readDataFromAPI(确保您没有使用空搜索值调用它)

<v-text-field
    v-model="search"
    append-icon="mdi-magnify"
    @click:append="readDataFromAPI()"
    placeholder="Type your search and press Enter"
    @keydown.enter="readDataFromAPI()"
    label="search"
    single-line
    hide-details
></v-text-field>
  1. 在您的 API 中,进行过滤和排序并将结果返回到前端,这应该是您所期望的。

祝你好运。

【讨论】:

  • 我们可以将@click 转换为 on change 吗?
  • 是的,您可以使用更改事件,但在用户离开搜索框之前它不会触发!并且用户不会期望这一点。
  • 也可以添加@keydown.enter 事件,通过回车键触发搜索逻辑。我更新了答案以显示这一点。请参阅 v-text-field 部分。
  • LOOOL 谢谢。最佳答案。我用 @input="" 工作。
猜你喜欢
  • 2018-08-07
  • 2021-12-16
  • 1970-01-01
  • 2013-09-16
  • 2014-07-19
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多