Connect a designated button to a designated modal for a seamless user experience

I am struggling to dynamically change the content of a modal based on different buttons being clicked. The issue lies in trying to reference the div element within JavaScript since I can't have multiple elements with the same ID. As a newcomer to JS, this is quite confusing for me.

In its simplest form, I want each button to correspond with specific content in the modal; button 1 should open modal 1, and so on. I'm unsure about what modifications need to be made in my JS code to achieve this functionality.

Here is the link to the existing code.

<button id="modalbutton" class="modalbutton">Open Modal 1</button>
<button id="modalbutton" class="modalbutton">Open Modal 2</button>
<button id="modalbutton" class="modalbutton">Open Modal 3</button>

<!-- Content 1 -->
<div id="detailmodal" class="modal">
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>1 Modal Header</h2>
    </div>
    <div class="modal-body">
      <p>please link with 1</p>
      <p>Some other text...</p>
    </div>
    <div class="modal-footer"><h3>Modal Footer</h3></div>
  </div>
</div>

<!-- Content 2 -->
<div id="detailmodal" class="modal">
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>2 Modal Header</h2>
    </div>
    <div class="modal-body">
      <p>please link with 2</p>
      <p>Some other text...</p>
    </div>
    <div class="modal-footer"><h3>Modal Footer</h3></div>
  </div>
</div>

<!-- Content 3 -->
<div id="detailmodal" class="modal">
  <div class="modal-content">
    <div class="modal-header">
      <span class="close">&times;</span>
      <h2>3 Modal Header</h2>
    </div>
    <div class="modal-body">
      <p>please link with 3</p>
      <p>Some other text...</p>
    </div>
    <div class="modal-footer"><h3>Modal Footer</h3></div>
  </div>
</div>

Script:

// Get the <span> element that closes the modal
var span = document.getElementsByClassName('close')[0];

// Open the modal when user clicks a button
for (let i = 0; i < btn.length; i++) {
  btn[i].onclick = function() {
    modal.style.display = 'block';
  };
}

// Close the modal when <span> (x) is clicked
span.onclick = function() {
  modal.style.display = 'none';
};

// Close the modal when user clicks outside of it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = 'none';
  }
};

Answer №1

To distinguish between them, you can utilize the index

document.getElementsByClassName('modal')[i]

Give it a go now:

// Access the modal
    
    var modal = document.getElementById('detailmodal');
  
    // Grab the button that triggers the modal
    var btn = document.getElementsByClassName("modalbutton");
   
    // Grab the <span> element that closes the modal
    var span = document.getElementsByClassName("close");
    
    // When the user clicks the buttons, open the modal 
    for (let i = 0; i < btn.length; i++) {
        btn[i].onclick = function() {
            document.getElementsByClassName('modal')[i].style.display = "block";
        }
    }
    
    for (let i = 0; i < span.length; i++) {
       // When the user clicks on <span> (x), close the modal
        span[i].onclick = function() {
            document.getElementsByClassName('modal')[i].style.display = "none";
        }
    }
    
    // Close the modal when clicking outside of it
     for (let i = 0; i < window.length; i++) {
         window[i].onclick = function(event) {
             if (event.target == modal) {
                document.getElementsByClassName('modal')[i].style.display = "none";
             }
         }
     }
/* The Modal (background) */
.modal {
  display: none; /* Initially hidden */
  position: fixed; /* Stay in place */
  z-index: 1; /* On top */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Allow scrolling if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.4); /* Black with opacity */
}

/* Modal Content */
.modal-content {
    position: relative;
    float: right;
    background-color: #fefefe;
    margin: auto;
    padding: 0;
    border: 1px solid #888;
    max-width: 850px;
    width: 100%;
    height: 100%;
    box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
    -webkit-animation-name: animatetop;
    -webkit-animation-duration: 0.4s;
    animation-name: animatetop;
    animation-duration: 0.8s
}

/* Add Animation */
@-webkit-keyframes animatetop {
  from {right:-100px; opacity:0} 
  to {right:0; opacity:1}
}

@keyframes animatetop {
  from {right:-100px; opacity:0}
  to {right:0; opacity:1}
}
<button id="modalbutton" class="modalbutton">Open Modal 1</button>

<button id="modalbutton" class="modalbutton">Open Modal 2</button>

<button id="modalbutton" class="modalbutton">Open Modal 3</button>

<!-- Content 1 -->
<div id="detailmodal" class="modal">

<!-- Modal content -->
<div class="modal-content">
  <div class="modal-header">
    <span class="close">&times;</span>
    <h2>1 Modal Header</h2>
  </div>
  <div class="modal-body">
    <p>please link with 1</p>
    <p>Some other text...</p>
  </div>
  <div class="modal-footer">
    <h3>Modal Footer</h3>
  </div>
</div>

</div>

<!-- Content 2 -->
<div id="detailmodal" class="modal">

<!-- Modal content -->
<div class="modal-content">
  <div class="modal-header">
    <span class="close">&times;</span>
    <h2>2 Modal Header</h2>
  </div>
  <div class="modal-body">
    <p>please link with 2</p>
    <p>Some other text...</p>
  </div>
  <div class="modal-footer">
    <h3>Modal Footer</h3>
  </div>
</div>

</div>

<!-- Content 3 -->
<div id="detailmodal" class="modal">

<!-- Modal content -->
<div class="modal-content">
  <div class="modal-header">
    <span class="close">&times;</span>
    <h2>3 Modal Header</h2>
  </div>
  <div class="modal-body">
    <p>please link with 3</p>
    <p>Some other text...</p>
  </div>
  <div class="modal-footer">
    <h3>Modal Footer</h3>
  </div>
</div>

</div>

Answer №2

It's important to avoid using multiple ids in your code, as you mentioned. One solution is to assign a unique id to each button (such as modalbutton1, modalbutton2, etc.). Then, you can use JavaScript to retrieve a reference to each button:

var modal1 = document.getElementById('modalbutton1');
var modal2 = document.getElementById('modalbutton2');

Next, you can attach an onclick handler to each button reference:

modal1.onclick=function(){ //Add your custom styling here }
modal2.onclick=function(){ //Add your custom styling here }

Answer №3

When working with static HTML content and non-dynamic modal data, it is safer to use multiple IDs to avoid any issues. Using the same ID for multiple buttons and div tags can lead to problems if the modals are not in a specific order.

It is recommended to structure your code like this:

btns = document.querySelectorAll('[id*=modalbutton-]');

for (let i = 1; i <= btns.length; i++) {
    var modalClassName = 'detailmodal-';

    btn = document.getElementById('modalbutton-' + i);     
    closeBtn = document.querySelector('#' + modalClassName + i + ' .close');

    closeBtn.onclick = function() {
        modal = document.getElementById(modalClassName + i);
        modal.style.display = "none";
    }

    btn.onclick = function() {
        modal = document.getElementById(modalClassName + i);
        modal.style.display = "block";
    }
}

Here is the suggested HTML pattern for buttons and modals:

<button id="modalbutton-1" class="modalbutton">Open Modal 1</button>
<div id="detailmodal-1" class="modal">

<button id="modalbutton-2" class="modalbutton">Open Modal 2</button>
<div id="detailmodal-2" class="modal">

If utilizing multiple IDs is not feasible, using data attributes with unique values is a good alternative. You can modify the code above to utilize attribute values to display the correct modal.

<button id="modalbutton" data-button-id="1" class="modalbutton">Open Modal 1</button>
<div id="detailmodal" data-modal-id="1" class="modal">

Adjust your loop as follows:

for (let i = 0; i < btn.length; i++) {
    btn[i].onclick = function(event) {
        var btnId = event.target.getAttribute("data-button-id");
        var modal = document.querySelector("[data-modal-id='" + btnId +"']");
        modal.style.display = "block";
    }
}

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

Learn the step-by-step process of sending an email through the SendGrid API V3 utilizing templates with a comprehensive example

Currently, I am delving into the SendGrid documentation regarding templates and stumbled upon this: You have three options to send transactional templates: Utilizing the SMTP Relay Including the template ID in the templates parameter of the W ...

What is the best way to implement automatic scrolling to the bottom of a materialUI drawer in React after a page refresh?

I am facing an issue with my Material UI Drawer, which contains numerous checkboxes and radio buttons for an advanced search page. Whenever a checkbox or radio button is clicked, it triggers an API request to fetch results instantly without requiring a sub ...

Differences: Angular ngController vs Controller embedded in Directive

I'm interested in exploring the various scenarios where these two methods of creating a controller can be used: Using ngController: myApp.controller('myController', ['$scope', function ( $scope ) { }]); Creating the controller ...

What is the best way to invoke the datepicker function on all rows of table data that share the 'datepicker' class?

Hey there! I'm working with a table that features a JavaScript function for a datepicker, as well as the ability to add and delete rows. The challenge I'm facing is that each new row created has the same ID as the previous one. How can I ensure t ...

unable to employ angular ui-sortable

I got the most recent source code from https://github.com/angular-ui/ui-sortable. However, I am facing issues in using it. The demo.html file seems to be broken. Update: Upon inspecting the console when opening demo.html: Navigated to https://www.google. ...

Utilize mongoose-delete to bring back items that have been marked for deletion but are still

Whenever I remove an item from my list, it switches the properties of the data to true, marking it as deleted and moves it to the trash. However, when I try to restore the item from the trash, the deleted properties are no longer available and the data rea ...

Having trouble getting my angular form validation to function properly

Even though I disabled Bootstrap's validation while using Angular, the validation for every input field still doesn't work. It seems like I have everything set up correctly. My code looks like this below with no success on input validation: < ...

Anticipated the server's HTML to have a corresponding "a" tag within it

Recently encountering an error in my React and Next.js code, but struggling to pinpoint its origin. Expected server HTML to contain a matching "a" element within the component stack. "a" "p" "a" I suspect it may be originating from this section of my c ...

Use JavaScript to identify and color the intersecting area of two triangles that overlap on a webpage

I created two triangular divs using HTML and I am utilizing jQuery UI to enable them to be draggable. Now, my goal is to overlap these two triangles and change the color of the overlapping area to a different shade. Here is an example: https://i.sstatic. ...

Skip nodes in Polymer 1.0 by using ExcludeLocalNames

I recently attempted to transition from Polymer version 0.5 to 1.0 and came across a particular question: Is there a way to exclude certain nodes inside a paper-menu? In the previous version (0.5), you could use the attribute excludedLocalNames to achieve ...

What is the best way to deliver an HTTP request from the controller to my Ajax function?

Is there a way to send HTTP OK and error responses from the controller to my AJAX request? For example, using HttpStatusCode.OK and HttpStatusCode.BadRequest. When I inspect in my browser it shows impresion.js 304 not modified. $(document).ready(functi ...

Retrieve all items from the firebase database

I have a query. Can we fetch all items from a particular node using a Firebase cloud function with an HTTP Trigger? Essentially, calling this function would retrieve all objects, similar to a "GET All" operation. My next question is: I am aware of the onW ...

What is the correct way to access the `this.' object in Vue.js when it's exported

When dealing with files containing simple data like mutation.js for vuex, the structure often looks similar to this example: export default { ... someFunction() {} ... } Currently, I am facing an issue where I am unable to access this. in order to uti ...

Tried to enroll the RCTBridgeModule category as RCTFileReaderModule

Trying to register the RCTBridgeModule class RCTFileReaderModule with the name 'FileReaderModule' failed because the name was already taken by the FileReaderModule class. This issue arises when attempting to launch an application on iOS using th ...

The error message "TypeError: Cannot read property 'then' of undefined" is commonly seen in Promises and Express 4.x

[UPDATE] I encountered an issue while attempting to incorporate the promise, resulting in the following error message: TypeError: Cannot read property "then" of undefined getResult(options1).then(function(body){... let options1 = {...}; app.post("/web ...

Steps for deactivating the submit button once confirming the presence of the username and email

When using AJAX to verify the existence of an email or username in the database, I want to deactivate the submit button if either one (or both) already exist. Currently, I have successfully changed the input border color but I am facing a challenge with t ...

Having difficulty updating an angular variable within a callback function

Currently, I am utilizing the Google Maps directions service to determine the estimated travel time. this.mapsAPILoader.load().then(() => { const p1 = new google.maps.LatLng(50.926217, 5.342043); const p2 = new google.maps.LatLng(50.940525, 5.35362 ...

Creating a process to automatically generate an input field upon the selection of checkboxes

Is there a way to automatically generate a text field for each checked box in a dynamically changing checkbox list? Below is my code snippet: <div> <label> Products </label> <li ng-repeat="item in INDproducttypes"> ...

Storing Node_modules in a separate directory

All my node modules are located in the path C:/Users/user/AppData/Roaming/npm/node_modules. I am attempting to include these node modules with babel and babel-presets for my webpack scripts. Here is my webpack.config.js module.exports = { context: &a ...

Vue and Jexcel: maximizing efficiency with event handling and dynamic calculations

I am trying to utilize the vue wrapper for jexcel and want to trigger the undo function from the toolbar computed field. However, I am facing difficulties accessing the spreadsheet instance as it throws an error saying 'this.undo is undefined.' ...