Kaddy03
Kaddy03

Reputation: 109

Vue.js - Modal seems to be not working inside a table

My goal is to have a button that will show a specific data in each row using a dialog or modal box. first I will show my script code for creating a dialog in my main index file:

<!-- DIALOG ELEMENT REGISTRY -->
    <script>
      var dialog = document.querySelector('dialog');
      //UNCOMMENT THE FOLLOWING CODE BELOW IF THIS APP WILL BE RUN IN OTHER BROWSERS OTHE THAN CHROME AND OPERA
      if (!dialog.showModal) {
       dialogPolyfill.registerDialog(dialog);
      }
    </script>

and here's my code for one of the components:

  <table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">
            <thead>
              <tr>
                <th class="mdl-data-table__cell--non-numeric">Product Type</th>
                <th>Measurements</th>
                <th>Quantity</th>
                <th>Preferred Tailor</th>
                <th>Customer Info</th>
                <th>Accept Order</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="order in orders">
                <td class="mdl-data-table__cell--non-numeric">{{ order.productType }}</td>
                <td>
                <button class="mdl-button mdl-js-button mdl-js-ripple-effect" v-on:click.prevent="showDialog">
                  See Measurements
                </button>
                <dialog class="mdl-dialog">
                  <h4 class="mdl-dialog__title">Customer's measurements</h4>
                  <div class="mdl-dialog__content">
                    {{ order.id }}
                  </div>
                  <div class="mdl-dialog__actions">
                    <button id="add" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored">
                      <i class="material-icons">done</i>
                    </button>
                  </div>
                </dialog>
                </td>
                <td>{{ order.quantity }}</td>
                <td>{{ order.tailorShops }}</td>
                <td>
                <button class="mdl-button mdl-js-button mdl-js-ripple-effect">
                  See customer info
                </button>
                <!-- DIALOG FOR MEASUREMENTS -->
                <dialog class="mdl-dialog" id="dialogBox">
                  <h4 class="mdl-dialog__title">Customer's measurements</h4>
                  <div class="mdl-dialog__content">
                    {{ order.id }}
                  </div>
                  <div class="mdl-dialog__actions">
                    <button id="add" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored">
                      <i class="material-icons">done</i>
                    </button>
                  </div>
                </dialog>
                </td>
                <td>
                  <button id="accept" class="mdl-button mdl-js-button mdl-button--icon">
                    <i class="material-icons">assignment_turned_in</i>
                  </button>
                </td>
              </tr>
            </tbody>
          </table>

and here's the script for the button for dialog:

methods: {
    showDialog: function(){
      dialog.showModal();
    }
  }

it was supposed to display a button in a column that will be clicked to show the id (for now) of the corresponding row of the table. but when I click the button in that column an error says that Uncaught TypeError: Cannot read property 'showModal' of null

I don't understand because it worked perfectly fine on the other page where I didn't put it inside a table. So I'm assuming that the dialog element being inside the table is causing the error.

Is my assumption right? what am I missing in my code?

Upvotes: 2

Views: 2029

Answers (1)

Bert
Bert

Reputation: 82499

This code:

var dialog = document.querySelector('dialog');

if (!dialog.showModal) {
  dialogPolyfill.registerDialog(dialog);
}

initializes one dialog element. But the code is now potentially rendering many dialogs (because there is more than one row in a table). I suspect you want to initialize all the dialogs using querySelectorAll and looping through the results. This initialization code will need to be handled in the mounted lifecycle handler and you will need to keep track of which dialog to open when the button is clicked.

So yes, to a certain extent, rendering your code in a table caused it to break, but it's mainly because you now have potentially many dialogs.

Here is an example (requires a browser that supports the dialog element).

console.clear()

new Vue({
  el: "#app",
  data:{
    people: [
      {
        name: "Bob",
        message: "Hi Bob"
      },
      {
        name: "Mary",
        message: "Hello Mary"
      },
      {
        name: "Jane",
        message: "Howdy Jane"
      },
      
    ]
  }
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
  <table>
    <tr v-for="person, ndx in people">
      <td>{{person.name}}</td>
      <td>
        <button @click="$refs.messageDialog[ndx].showModal()">Say Hello</button>
        <dialog ref="messageDialog">
          {{person.message}}
          <button @click="$refs.messageDialog[ndx].close()">Close</button>
        </dialog>
      </td>
    </tr>
  </table>
</div>

Upvotes: 2

Related Questions