父组件只将动态v-modal ID传给分页中第一页的子组件。

问题描述 投票:0回答:1

我使用的是 [email protected][email protected]

我有一个名为 index.vue 和一个子组件来列出所有客户。customerModal.vue 以控制 v-modal 对于 EditCreate Cusotmer形式。

我使用的是 v-table 用按钮动作列出客户的详细信息

index.vue /customer create btn。

<!-- {{-- CREATE CUSTOMER --}} -->

    <b-button   @click="$root.$emit('bv::show::modal', 'customerModal' , $event.target)"  variant="success" title="Create New Customer">
        <i class="fas fa-plus-circle" id="action-icon" style="right:3%"></i>
    </b-button>  

    <!-- Modal Customer -->
    <customer-modal   :customers="customers"   modalType="create" @create-customer="customers.push($event)"></customer-modal>

index.vue /customer edit btn

<b-table
    show-empty 
    :filter="filter"
    @filtered="on_filtered"
    id="customers-table" 
    :sort-by.sync="sort_by"
    :sort-desc.sync="sort_desc"
    :items="customers" 
    :fields="fields" 
    :per-page="per_page" 
    :current-page="current_page" 
    responsive
    hover
    head-variant="light"
    class="text-center mt-4"
    >
        <template v-slot:cell(actions)="data">      
            <div class="btn-group" role="group">

                <!-- {{-- EDIT CUSTOMER --}} -->
                <b-button   @click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id, $event.target)" variant="primary" title="Edit Customer">
                    <i class="fas fa-edit"></i>
                </b-button>

                <!-- Customer Modal-->
                <customer-modal  modalType="edit" :selectedCustomer="data.item" :customers="customers" @update-customer="data.item = $event"></customer-modal>

            </div>                
        </template>

index.vue /b-pagination

            <b-pagination
                        class=" m-auto justify-content-center"
                        pills
                        :per-page="per_page"
                        :total-rows="rows"
                        v-model="current_page"
                        aria-controls="#customers-table"

                    >
            </b-pagination>

客户模式.vue

       <b-modal
            :id="this.customer.first_name.replace(/\s/g, '')+this.customer.id || 'customerModal'"
            title="Customer Modal"
            @hidden="resetModal"
            hide-footer
        >

问题

当我使用 b-pagination btn edit 不显示相应的v-modal。而在第一页中,所有的 edit 每个客户的btns都能正常工作。

enter image description here

然而,如果我添加 create 将btn添加到第二页的列表中,就可以了。enter image description here

vue.js bootstrap-vue
1个回答
1
投票

问题是Vue试图在第1页重用你的模式,以节省重新渲染的费用。

问题的根源是在模态组件中,你设置了 this.customerthis.selectedCustomercreate 钩,而不是其他地方。由于 create 在第2页又不运行了,它不会更新了 this.customer 意味着ID仍然会与第1页的行相匹配。

从长远来看,你可能需要重新考虑这个逻辑。

但是你应该可以通过添加以下内容来解决这个问题。:key="data.item.id"customer-modal的时候,迫使Vue重新渲染模式。id 更新。所以它不能尝试在各个页面中重用模式。

<customer-modal  modalType="edit" :selectedCustomer="data.item" :customers="customers" @update-customer="data.item = $event" :key="data.item.id"></customer-modal>

工作片段(基于这个网站的codepen) Github问题.

Vue.use(window.vuelidate.default);
const { required, email, numeric, minLength, maxLength } = window.validators;
let OMDModal = {
  props: ["selectedCustomer", "modalType", "customers"],
  template: '#customer-modal',
  validations: {
    customer: {
      first_name: {
        required,
        minLen: minLength(3),
        maxLen: maxLength(12)
      },
      last_name: {
        required,
        minLen: minLength(3),
        maxLen: maxLength(12)
      },
      email: {
        required,
        email,
        isUnique: function (val) {
          if (val === "") return true;
          else if (val === this.currentEmail) return true;
          return axios.get(`api/validateEmail/${val}`).then((res) => {
            return res.data.unique;
          });
        }
      }
    }
  },
  data() {
    return {
      currentEmail: "",
      alert_sec: 0,
      alert_duration: 5,
      alert_message: "",
      alert_color: "",
      customer: {
        id: "",
        first_name: "",
        last_name: "",
        email: ""
      },
      customer_default: {
        first_name: [],
        last_name: [],
        email: []
      }
    };
  },
  watch: {
    "customer.first_name"(newVal, oldVal) {
      if (this.modalType === "edit") {
        this.customer_default.first_name.push(oldVal);
      }
    },
    "customer.last_name"(newVal, oldVal) {
      if (this.modalType === "edit") {
        this.customer_default.last_name.push(oldVal);
      }
    },
    "customer.email"(newVal, oldVal) {
      if (this.modalType === "edit") {
        this.customer_default.email.push(oldVal);
      }
    }
  },
  computed: {
    ModalID() {
      if (this.modalType === "create") {
        return "customerModal";
      } else {
        return this.customer.first_name.replace(/\s/g, "") + this.customer.id;
      }
    },
    now() {
      const monthNames = [
        "Jan",
        "Feb",
        "Mar",
        "Apr",
        "May",
        "Jun",
        "Jul",
        "Aug",
        "Sep",
        "Oct",
        "Nov",
        "Dec"
      ];
      const today = new Date();
      let day = today.getDate().toString();
      let month = (today.getMonth() + 1).toString();
      let year = today.getFullYear().toString();
      return year + "-" + month + "-" + day;
    },
    first_nameValidate() {
      if (this.$v.customer.first_name.$dirty) {
        return !this.$v.customer.first_name.$anyError;
      } else return null;
    },
    last_nameValidate() {
      if (this.$v.customer.last_name.$dirty) {
        return !this.$v.customer.last_name.$anyError;
      } else return null;
    },
    emailValidate() {
      if (this.$v.customer.email.$dirty) {
        return !this.$v.customer.email.$anyError;
      } else return null;
    }
  },
  methods: {
    setFirstName(e) {
      this.customer.first_name = e;
      this.$v.customer.first_name.$touch();
    },
    setLastName(e) {
      this.customer.last_name = e;
      this.$v.customer.last_name.$touch();
    },
    setEmail(e) {
      this.customer.email = e;
      this.$v.customer.email.$touch();
    },
    resetModal() {
      this.$nextTick(() => {
        this.$v.$reset();
      });
      if (this.modalType === "create") {
        this.customer = {
          id: "",
          first_name: "",
          last_name: "",
          email: ""
        };
      }

      if (this.alert_color != "success") {
        if (this.customer_default.first_name[1] != undefined) {
          this.customer.first_name = this.customer_default.first_name[1];
        }
        if (this.customer_default.last_name[1] != undefined) {
          this.customer.last_name = this.customer_default.last_name[1];
        }
        if (this.customer_default.email[1] != undefined) {
          this.customer.email = this.customer_default.email[1];
        }
      }
    },
    onSubmit(v, e) {
      v.customer.$touch();
      if (this.$v.customer.$anyError) {
        this.alert_message = "Correct the inputs Please";
        this.alert_color = "danger";
        this.show_alert();
      } else {
        this.customer.first_name =
          this.customer.first_name.charAt(0).toUpperCase() +
          this.customer.first_name.slice(1);
        // CREATE CUSTOMER
        if (this.modalType === "create") {
          this.customer.created_at = this.now;
          let last_index = this.customers.length - 1;
          let last_customer = this.customers[last_index];
          this.customer.id = last_customer.id + 1;
          fetch(`api/customers`, {
            method: "POST",
            body: JSON.stringify(this.customer),
            headers: { "content-type": "application/json" }
          })
            .then((res) => res.json())
            .then((res) => {
              this.$nextTick(() => {
                this.$v.$reset();
              });
              this.$bvModal.hide(
                this.customer.first_name.replace(/\s/g, "") +
                  this.customer.id || "customerModal"
              );
              this.$emit("create-customer", this.customer);
              this.customer = {
                id: "",
                first_name: "",
                last_name: "",
                email: ""
              };
            })
            .catch((e) => console.log(e));
        } else {
          // UPDATE CUSTOMER
          this.customer.updated_at = this.now;
          fetch(`api/customers/${this.customer.id}`, {
            method: "put",
            body: JSON.stringify(this.customer),
            headers: {
              "content-type": "application/json"
            }
          })
            .then((res) => res.json())
            .then((data) => {
              this.$nextTick(() => {
                this.$v.$reset();
                this.$bvModal.hide(
                  this.customer.first_name.replace(/\s/g, "") +
                    this.customer.id || "customerModal"
                );
              });
              this.$emit("update-customer", this.selectedCustomer);
              this.alert_color = "success";
              this.alert_message = "Customer Updated Successfully";
            })
            .catch((error) => console.log(error));
        }
      }
    },
    show_alert() {
      this.alert_sec = this.alert_duration;
    },
    countDown(alert_sec) {
      this.alert_sec = alert_sec;
    }
  },
  created() {
    if (this.modalType === "edit") {
      this.customer = this.selectedCustomer;
      this.currentEmail = this.selectedCustomer.email;
    }
  }
};


window.onload = () => {
  new Vue({
    el: "#app",
    data() {
      return {
        per_page: 3,
        current_page: 1,
        fields: [
          { key: "#", sortable: false },
          { key: "id", sortable: true },
          { key: "first_name", label: "Name", sortable: true, class: "w-25" },
          { key: "email", sortable: true },
          { key: "actions", sortable: false }
        ],
        sort_by: "email",
        sort_desc: false,
        filter: null,
        filter_on: [],
        customers: [],
        customer: {
          id: "",
          first_name: "",
          last_name: "",
          email: ""
        }
      };
    },
    computed: {
      now() {
        const monthNames = [
          "Jan",
          "Feb",
          "Mar",
          "Apr",
          "May",
          "Jun",
          "Jul",
          "Aug",
          "Sep",
          "Oct",
          "Nov",
          "Dec"
        ];
        const today = new Date();
        let day = today.getDate().toString();
        let month = (today.getMonth() + 1).toString();
        let year = today.getFullYear().toString();
        return year + "-" + month + "-" + day;
      },
      rows() {
        return this.customers.length;
      }
    },
    methods: {
      fetchCustomers() {
        fetch("https://reqres.in/api/users")
          .then((res) => res.json())
          .then((res) => {
            this.customers = res.data;
          })
          .catch((err) => console.log(err));
      },
      on_filtered(filtered_items) {
        this.rows;
      },
      openModal(id) {
        this.$root.$emit('bv::show::modal', id)
      }
    },
    created() {
      this.fetchCustomers();
    },
    components: {
      "omd-modal": OMDModal
    }
  });
};
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>


<div id="app">
  <div class="card">
    <div class="card-body">
      <!-- Card Header (Title & Create btn) -->
      <div class="row ">
        <div class="col-sm-4">
          <h4 class="card-title font-weight-bold">
            User Management
          </h4>
        </div>
        <div class="col-sm-4 offset-sm-4">
          <div class="btn-toolbar float-right">
            <!-- {{-- CREATE CUSTOMER --}} -->
            <b-button @click="$root.$emit('bv::show::modal', 'customerModal', $event.target)" variant="success" title="Create New Customer">
              CREATE
            </b-button>
          </div>
        </div>
      </div>

      <!-- Modal Customer Create -->
      <omd-modal :customers="customers" modal-type="create" @create-customer="customers.push($event)"></omd-modal>

      <!-- Search Bar -->
      <div class="row">
        <div class="col-12">
          <b-input-group class="w-50 m-auto">
            <b-form-input placeholder="Search for Customers" v-model="filter" class="rounded-pill searchbar">
            </b-form-input>
          </b-input-group>
        </div>
      </div>

      <!-- Customer List (Card Content)  -->
      <div class="row ">
        <div class="col">
          <b-table ref="table" :key="customer.id" show-empty :filter="filter" @filtered="on_filtered" id="customers-table" :sort-by.sync="sort_by" :sort-desc.sync="sort_desc" :items="customers" :fields="fields" :per-page="per_page" :current-page="current_page" responsive hover head-variant="light" class="text-center mt-4">
            <template v-slot:cell(#)="data">
              {{data.index+1}}
            </template>
            <template v-slot:cell(first_name)="data">
              {{data.item.first_name}} {{data.item.last_name}}
            </template>

            <template v-slot:cell(actions)="data">
              <div class="btn-group" role="group">

                <!-- {{-- EDIT CUSTOMER --}} -->
                <b-button @click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id)" variant="primary" title="Edit Customer">
                  Edit
                </b-button>
              </div>

              <!--Edit Customer Modal-->
              <omd-modal modal-type="edit" :selected-customer="data.item" :customers="customers" @update-customer="data.item = $event" :key="data.item.id"></omd-modal>
            </template>
          </b-table>
        </div>
      </div>

      <hr>
      <!-- {{-- Card Footer --}} -->
      <div class="row">
        <div class="col-sm-4">
          <small class="text-muted"> Total Customers {{rows}} </small>
        </div>

        <div class="col-sm-4">
          <b-pagination class=" m-auto justify-content-center" pills :per-page="per_page" :total-rows="rows" v-model="current_page" aria-controls="#customers-table">
          </b-pagination>
        </div>
      </div>
    </div>
  </div>
</div>

<template id="customer-modal">
  <b-modal :id="customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal'" title="Customer Modal" @hidden="resetModal" hide-footer>
    <b-alert id="alert" style="width: 100%;" :show="alert_sec" dismissible :variant="alert_color" @dismissed="alert_sec=0" @dismiss-count-down="countDown">
      {{alert_message}}
    </b-alert>
    <b-form @submit.prevent="onSubmit($v, $event)">
      <!-- first_name -->
      <b-form-group id="first-name-group" label="First Name" label-for="first-name">

        <b-form-input id="first-name" type="text" :value="customer.first_name" :state="first_nameValidate" @change="setFirstName($event)" required></b-form-input>

        <b-form-invalid-feedback :state="first_nameValidate">First Name is required and must be 3-5 character long.</b-form-invalid-feedback>
      </b-form-group>

      <!-- Last_name -->
      <b-form-group id="last-name-group" label="Last Name" label-for="last-name">
        <b-form-input id="last_name" :value="customer.last_name" :state="last_nameValidate" @change="setLastName($event)" type="text" required>
        </b-form-input>
        <b-form-invalid-feedback :state="last_nameValidate">Last Name is required and must be 3-5 character long.</b-form-invalid-feedback>
      </b-form-group>

      <!-- Email -->
      <b-form-group id="email-group" label="Email" label-for="email">
        <b-form-input id="email" :state="emailValidate" :value="customer.email" @change="setEmail($event)" type="email" required>
        </b-form-input>
        <b-form-invalid-feedback :state="emailValidate">Invalid Email.</b-form-invalid-feedback>
      </b-form-group>

      <hr style="margin-top: 2rem; margin-bottom: 1rem;">
      <div class="row justify-content-center">
        <b-button variant="success" class="mr-1" type="submit">Save Changes</b-button>
        <b-button variant="danger" class="ml-1" @click="$bvModal.hide(customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal')">Cancel</b-button>
      </div>
    </b-form>

  </b-modal>
</template>

<script src="https://unpkg.com/[email protected]/dist/validators.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.