Launch a modal by clicking a button located in a separate component using Vue JS

I am dealing with 2 components: TestSearchTool and TestModal. My goal is to display the Modal when a button in the TestSearchTool component is clicked. These two components are siblings in the hierarchy, so I am struggling to pass values between them (even though Vuex is an option, I prefer a solution without it). I am utilizing Bootstrap 5 and Vue 3 for this task since Bootstrap Vue does not function with Vue 3.

Below is the code for my TestModal component:

<template>
<div>
  <div class="modal fade" ref="exampleModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
          <button type="button" class="btn-close" @click="modal.hide()" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          ...
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" @click="modal.hide()">Close</button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div>
    </div>
  </div>
  </div>
</template>
<script>
import { Modal } from 'bootstrap'
export default {
  name: "App",
  data: () => ({
    modal: null
  }),
  mounted() {
    this.modal = new Modal(this.$refs.exampleModal)
  }
};
</script>

The following code snippet shows my TestSearchTool component:

<template>
  <div>
      <div class="container ml-5 mt-3 border-1 rounded pl-5 pt-5 pr-5">
          <div class="row mb-4">
             <div class="col-md-6 mb-4" >
          <label for="test" class="label-form">Titre</label>
          <input autocomplete="off" placeholder="Rechercher par le titre du test" v-model="testName" type="text"  id="test" class="form-control">
          </div>
             <div class="col-md-6 mb-4">
            <label for="candidat" class="label-form">Candidat</label>
          <select  v-model="CandidateName" class="form-select" id="candidat">
            <option  value="" selected>Tous les candidats</option>
          </select>
          </div>
             </div>
             <div class="row">
               <div class="col-12 mb-3">
                 <div class="col-12 mb-4">
                   <div class="col-sm-6 col-12 d-inline-block">
                     <!-- Modal is shown on this button's click !-->
                    <button  type="button" @click="this.$emit('clickDone')" class=" btn btn-primary col-12 col-sm-11 mb-sm-0 mb-sm-0 mb-4 float-sm-left"><i class="fa-solid fa-file-circle-plus"></i> Ajouter Un Test</button>
                    </div>
                    <div class="col-sm-6 col-12 d-inline-block">
                      <button  @click="deleteTests" type="button" class=" btn btn-primary col-sm-12 col-12" v-if="false"><i class="fa-solid fa-file-circle-minus"></i>  Supprimer Le(s) Test(s)</button>
                    </div>
                  </div>
              <button id="searchTest" @click="searchBy" class="col-12 btn btn-primary" ><i class="fas fa-search"></i> Rechercher</button>
             </div>
             
          </div>
            
          </div>
  </div>
</template>

<script>
export default {
components:{
},
data(){
    return {
        testName:'',
        CandidateName:'',
        show:false,
    }
},
methods:{
},
}
</script>

<style scoped>
</style>

Lastly, here is the parent component named "Tests":

<template>
  <div>
  
     <test-search-tool></test-search-tool>
     
  <test-modal></test-modal>
  </div>
</template>

<script>
import TestSearchTool from "../components/TestSearchTool.vue"
import TestModal from "../components/TestModal.vue"
export default {
components : {
    DashboardNavbar,
    TestSearchTool,
    TestModal,
},
mounted(){
      document.body.style.backgroundImage='url("")';
      document.body.style.background="white";
      
}
}
</script>

<style>

</style>

Answer №1

When writing code for components, the main aim is to assign specific responsibilities or tasks to each component. For instance, a "modal" component is expected to display modal content. Therefore, it would be inaccurate to consider the modal component (named TestModal.vue) and TestSearchTool.vue as siblings. You can utilize the TestModal.vue component in any part of your app structure where modal content needs to be displayed. In essence, the TestModal.vue component does not require any special content or logic to directly link it as a child of Tests.vue (the parent component).

In line with the explanation above, I've utilized TestModal.vue as a child component of TestSearchTool.vue. By leveraging props, watch, and emit functionalities of Vue, here are the codes for all three components:

TestSearchTool.vue:

<template>
  <div>
    <div class="container ml-5 mt-3 border-1 rounded pl-5 pt-5 pr-5">
      <div class="row mb-4">
        <div class="col-md-6 mb-4" >
          <label for="test" class="label-form">Titre</label>
          <input autocomplete="off" placeholder="Rechercher par le titre du test" v-model="testName" type="text"  id="test" class="form-control">
        </div>
        <div class="col-md-6 mb-4">
          <label for="candidat" class="label-form">Candidat</label>
          <select  v-model="CandidateName" class="form-select" id="candidat">
            <option  value="" selected>Tous les candidats</option>
          </select>
        </div>
      </div>
      <div class="row">
        <div class="col-12 mb-3">
          <div class="col-12 mb-4">
            <div class="col-sm-6 col-12 d-inline-block">
              <!-- Modal is shown on this button's click !-->
              <button  type="button" @click="this.$emit('clickDone')" class=" btn btn-primary col-12 col-sm-11 mb-sm-0 mb-sm-0 mb-4 float-sm-left"><i class="fa-solid fa-file-circle-plus"></i> Ajouter Un Test</button>
            </div>
            <div class="col-sm-6 col-12 d-inline-block">
              <button  @click="deleteTests" type="button" class=" btn btn-primary col-sm-12 col-12" v-if="false"><i class="fa-solid fa-file-circle-minus"></i>  Supprimer Le(s) Test(s)</button>
            </div>
          </div>
          <!-- *********************** -->
          <!-- this button is responsible for showing modal. you can use such a button in other parts of your app if you define "data" correctly -->
          <button id="searchTest" @click="dataModal = true" class="col-12 btn btn-primary" ><i class="fas fa-search"></i> Rechercher</button>
        </div>

        <test-modal @closeModal="dataModal = false" :showModal="dataModal"></test-modal>
        <!-- *********************** -->
      </div>

    </div>
  </div>
</template>

<script>
import TestModal from "../components/TestModal.vue"
export default {
  name: "TestSearchTool",
  components:{
    TestModal
  },
  data(){
    return {
      testName:'',
      CandidateName:'',
      show:false,
      /* this data is used for showing modal */
      dataModal: false
    }
  }
}
</script>

<style scoped>
</style>

TestModal.vue:

<template>
  <div>

    <div id="myModal" class="modal fade" ref="exampleModal" tabindex="-1" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
            <button type="button" class="btn-close" @click="hideModal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="hideModal">Close</button>
            <button type="button" class="btn btn-primary">Save changes</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { Modal } from 'bootstrap'
export default {
  name: "TestModal",
  data: () => ({
    modalInstance: null
  }),
  props: {
    showModal: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    showModal(newValue, oldValue) {
      console.log(newValue);
      if (newValue === true) {
        this.modalActive();
      }
    }
  },
  methods: {
    modalActive: function () {
      this.modalInstance = new Modal(document.getElementById('myModal'), {
        target: "#my-modal",
        backdrop: "static"
      });
      this.modalInstance.show()
    },
    hideModal: function () {
      console.log("closed");
      this.modalInstance.hide();
      this.$emit('closeModal');
    }
  }
};
</script>

<style scoped>

</style>

Tests.vue:

<template>
  <div>
    <test-search-tool></test-search-tool>
  </div>
</template>

<script>
import TestSearchTool from "../components/TestSearchTool.vue"

export default {
  name: "Tests",
  components : {
    TestSearchTool
  }
}
</script>

<style scoped>

</style>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble incorporating an API module into a nested component in Vue

I have encountered a perplexing issue when attempting to import an API module into a nested component within a Vue application. After simplifying the problem as much as possible, I created a codesandbox example to demonstrate it. The problem arises when ...

Looking to merge two components into one single form using Angular?

I am currently developing an Angular application with a dynamic form feature. The data for the dynamic form is loaded through JSON, which is divided into two parts: part 1 and part 2. // JSON Data Part 1 jsonDataPart1: any = [ { "e ...

Concealing specific outcome by implementing jQuery and AJAX with a database

I have an HTML list that appears as follows: <ul> <li>something</li> <li>something1</li> <li>something2</li> <ul> <div class="randomwrapper"> <img src="<?php echo $databaseresult[$i];?& ...

Enhance the color scheme of your collapsed or expanded Bootstrap NAV for mobile devices

Currently working on customizing the navbar using Bootstrap. I've been able to style it perfectly for both desktop and mobile devices in its initial state. The issue arises when attempting to style the navbar in its expanded and collapsed states on m ...

What is the process for adding images from CSS (backgrounds, etc.) to the build folder with webpack?

Trying out the file loader for processing images and adding them to my build folder. Images within HTML files successfully show up in the build, but the ones from styles do not. I've divided my webpack configuration into two separate files and use t ...

Can different classes be assigned as "dragenter" targets?

Is it possible to apply the Jquery "dragenter" event to multiple targets or classes simultaneously? I tried this approach, but it doesn't seem to be working: $('.list').on('dragenter','.class1, .class2', function(e) { ...

The initial transition in offcanvas on bootstrap 5 is not appearing when a placement is dynamically added

I am currently working on triggering an Offcanvas with JS and making the placement configurable. The issue arises when attempting to dynamically set the offcanvas-end class to the offcanvas element, as it does not transition smoothly the first time it is t ...

Error: CSRF token not found or invalid. What is the procedure for transmitting a CSRF token from the frontend to the backend?

In my Django project, I have a task that involves sending a date string from the frontend to the backend. On the frontend, I am utilizing JavaScript's fetch method. async function getCustomerInDeliveryDate(deliveryDate : String) { con ...

JavaScript Website Struggling to Make Postman REST API Call to Parse Server

I have set up a Parse API Server on Azure and can successfully make REST API calls to it using Postman. However, when I try to replicate this process in my web app using the jQuery AJAX code snippet generated by Postman, I encounter a 400 (bad request) err ...

Guide to importing a JSON file into Vue.js and HTML

I'm a beginner in Vue and not very familiar with HTML I'm attempting to import data from a JSON file into my interface to display it for the user. Below is the structure of the JSON: [ { "Title": "SOFT-STARTER", "Cod&q ...

Integrate React tags with Redux form to ensure the values are transmitted as an array within the payload

I am currently working on a redux-form that contains a component for tags. I am struggling to figure out how to retrieve the tag values in an array as a payload. Any help would be greatly appreciated. Below is the code snippet for the tags component: ...

Vue Draggable not working on touch devices - drop function not being activated

I've been developing a website that needs to be responsive on both desktop and tablets. One of the features includes three columns where users can drag orders from one column to another. Sometimes, upon dropping an order, the user must answer question ...

Malfunctioning Bootstrap collapse feature

I am experiencing an issue with my modal that contains 2 blocks. When I click on the .emailInbound checkbox, it opens the .in-serv-container, but when I click on the .accordion-heading to reveal the comment section, the .in-serv-container collapses. What c ...

What guidelines should be followed for utilizing jQuery's Ajax convenience methods and effectively managing errors?

Imagine a scenario where I am trying to mimic Gmail's interface using jQuery Ajax to incorporate periodic auto-saving and sending functionalities. Error handling is crucial, especially in cases of network errors or other issues. Instead of just being ...

Do you typically define a static variable within a function using `this.temp`?

I am looking to implement a static variable within a function that meets the following criteria: It maintains its value across multiple calls to the function It is only accessible within the scope of that function Below is a basic example of how I am mee ...

Struggling to make the javascript function compatible with the drop-down menu

I'm encountering issues with making my JavaScript work properly alongside my HTML. Specifically, I want the "activity" drop-down box to function in conjunction with the "city" drop-down box. For instance, if I choose "Brisbane" and then select an acti ...

What is the best way to trigger a Vue.js page element update with fresh data?

My vuejs application utilizes vue-router with the specified routes: const routes = [ { path: '/list', component: list, alias: '/' }, { path: '/resources/:id?', component: resources }, { path: '/emails', compon ...

Unexpected "<" and dual output in jade include seem to defy explanation

i am currently redesigning my website to incorporate dynamic includes. These includes are pre-rendered on the server and then passed to res.render() however, I am encountering unexpected occurrences of < and > on the page, along with the issue of th ...

Twitter typeahead with a dynamic array of strings

Currently, I am making an ajax call to retrieve a list of objects. Once this array of objects is filled, a separate string[] is created with the names of these objects. My goal is to pass this data to Twitter Typeahead using a Bloodhound source. However, ...

Transferring ipywidgets to a web platform

I've developed a Python program in Jupyter Notebook that leverages the interact function from the ipywidgets module. interact(my_func, filter_by=filter_by_list, format_type=format_dict.keys()) I am looking for a way to share this interactive widget ...