1

There is a product page where product list component and action buttons are there. This is the parent component. That product list component consists of list table and edit/add modal. Now, problem is Add action event is in parent component. But, add modal related data is available in child component.

So, how can i open that model based on click event from parent? Here i am doing like this approach.

Parent Component(Product Component snippets )

<template>
  ..... other code ....
   <div class="action-buttons">
       <vu-button class="add-action" @click="onAddAction">
          <svg-icon
               fill="#0071E3"
               name="add"
               height="20"
               width="28"
           />
       </vu-button>
   </div>
 <ChildComponent :open-add-modal="isAddModal" />
</template>

Methods in Parent component

onAddAction() {
       this.editable = false;
       this.isAddModal = true;
    },

Now, in child component i passing boolean props openAddModal but i am checking condition into created hook to show Add modal.

Problem is in initial rendering or page load add modal is showing up not in click event. How can i solve this issue?

Child component(Created hook)

created() {
    if(this.openAddModal) {
         this.showModal = true;
         this.formType = 'add';
         this.editId = null;
  }
},

I want to show add modal based on click event from parent not in initial page load.

1
  • Is a v-for loopt? Makes a big difference ;) Also seems to me your initial value of isAddModal is true if it opens up during render. Please provide a MCVE Commented Apr 25, 2021 at 6:22

2 Answers 2

3

You can try using a watcher instead of checking the value of in the created hook. This way, when the prop in the child component changes, you can check the new value there and emit the needed data to the parent to then open the modal.

Example:

Parent component code

<template>
  <div>
    <p>Parent component</p>

    <button @click="changeOpenAddModal">Clic to get child data</button>
    <button @click="resetParent">Reset data in parent</button>
    <p>Data from child: {{ childData }}</p>

    <br />
    <br />
    <Child
      :openAddModal="this.openAddModal"
      @child-component-data-emit="this.setChildData"
    />
  </div>
</template>

<script>
import Child from "./Child";

export default {
  name: "Parent",
  components: { Child },
  data() {
    return {
      childData: null,
      openAddModal: false,
    };
  },
  methods: {
    changeOpenAddModal() {
      this.openAddModal = !this.openAddModal;
      console.log(
        "changing openAddModal data. New value is ",
        this.openAddModal
      );
    },
    setChildData(data) {
      console.log("setting child data", data);
      this.childData = data;
    },
    resetParent() {
      this.childData = null;
      this.changeOpenAddModal();
    },
  },
};
</script>

Child component code

<template>
  <div>
    <p>Child component</p>
  </div>
</template>

<script>
export default {
  name: "Child",
  props: {
    openAddModal: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      childData: {
        prop1: "lorem",
        prop2: "ipsum",
        prop3: "dolor",
      },
    };
  },
  watch: {
    openAddModal: function (newValue, oldValue) {
      console.log("child watcher with newValue", newValue);
      if (newValue) {
        this.$emit("child-component-data-emit", this.childData);
      }
    },
  },
  mounted: function () {
    console.log("prop openAddModal value on mounted:", this.openAddModal);
  },
};
</script>
Sign up to request clarification or add additional context in comments.

Comments

2

I have built a few modals with Vue 2 and Vue CLI, and use an alternate approach for showing, hiding, and determined if add or edit mode. No watch or separate add/edit mode boolean is necessary.

The 'product' processing is somewhat contrived since no database or AJAX are used in this example, but you should get be able to evaluate the functionality.

Parent.vue

<template>
  <div class="parent">
    <h4>Parent of Form Modal</h4>
    <div class="row">
      <div class="col-md-6">
        <button class="btn btn-secondary" @click="showAddModal">Show Add Modal</button>
        <button class="btn btn-secondary btn-edit" @click="showEditModal">Show Edit Modal</button>
      </div>
    </div>
    <form-modal v-if="displayModal"
      :parentProduct="product"
      @save-product-event="saveProduct"
      @close-modal-event="hideModal"
    />
  </div>
</template>

<script>
  import FormModal from './FormModal.vue'

  export default {
    components: {
      FormModal
    },
    data() {
      return {
        product: {
          id: 0,
          name: '',
          description: ''
        },
        displayModal: false
      }
    },
    methods: {
      showAddModal() {
        this.resetProduct();
        this.displayModal = true;
      },
      showEditModal() {
        this.product.id = 1;
        this.product.name = 'productEdit';
        this.product.description = 'productEditDescription';
        this.displayModal = true;
      },
      hideModal() {
        this.displayModal = false;
      },
      saveProduct(modalProduct) {
        this.product = modalProduct;
        this.hideModal();
        console.log(this.product);
      },
      resetProduct() {
        this.product.id = 0;
        this.product.name = '';
        this.product.description = '';
      }
    }
  }
</script>

<style scoped>
  .btn-edit {
    margin-left: 0.5rem;
  }
</style>

FormModal.vue

<template>
  <!-- The Modal -->
  <div id="form-modal" class="modal-dialog-container">
    <div class="modal-dialog-content">
      <div class="modal-dialog-header">
        <h4>{{ modalTitle }}</h4>
      </div>
      <div class="modal-dialog-body">
        <form @submit.prevent="saveProduct">
          <div class="form-group">
            <label for="product-name">Name</label>
            <input type="text" class="form-control" id="product-name" v-model="product.name">
          </div>
          <div class="form-group">
            <label for="product-description">Description</label>
            <input type="text" class="form-control" id="product-description" v-model="product.description">
          </div>
          <button type="submit" class="btn btn-primary">Submit</button>
          <button type="button" class="btn btn-secondary btn-close" @click="closeModal">Cancel</button>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    props: {
      parentProduct: {
        type: Object,
        required: true
      }
    },
    data() {
      return {
        product: this.parentProduct
      }
    },
    computed: {
      modalTitle() {
         return this.product.id === 0 ? 'Add Product' : 'Edit Product';
      }
    },
    methods: {
      closeModal() {
        this.$emit('close-modal-event');
      },
      saveProduct() {
        // Add product
        if (this.product.id === 0) {
          this.product.id = 2;
        }
        this.$emit('save-product-event', this.product);
      }
    }
  }
</script>

<style scoped>
  .modal-dialog-container {
    /* display: none; Hidden by default */
    position: fixed;
    /* Stay in place */
    z-index: 1;
    /* Sit on top */
    left: 0;
    top: 0;
    width: 100%;
    /* Full width */
    height: 100%;
    /* Full height */
    overflow: auto;
    /* Enable scroll if needed */
    background-color: rgb(0, 0, 0);
    /* Fallback color */
    background-color: rgba(0, 0, 0, 0.4);
    /* Black w/ opacity */
  }

  .modal-dialog-content {
    background-color: #fefefe;
    margin: 10% auto;
    padding: 20px;
    border: 1px solid #888;
    border-radius: 0.3rem;
    width: 30%;
  }

  .btn-close {
    margin-left: 0.5rem;
  }
</style>

1 Comment

Tim, very nicely explained.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.