2
votes

I have a Bootstrap modal that shows itself on this Vue method:

methods: {
    showAddSongModal() {
        $('#addSongModal').modal('show');
    }
}

This works in a project where the method is of the root Vue instance. However, I am now trying to use this modal and method in a Vue component. The method is invoked by @click="showAddSongModal() but when it's put inside a component, I get this error on click:

Uncaught TypeError: $(...).modal is not a function

Otherwise, the page loads without errors in Chrome Dev Tools. And what's more, typing $('#addSongModal').modal('show'); at the console behaves like it should -- the modal works!

Thus far, I checked:

  1. jQuery is called but once.
  2. jQuery, Bootstrap, Vue, Axios, et al. are called before my Vue components.

The fact that @click="showAddSongModal() works from the console should validate my build process, right?

Why does this modal and method work from a root Vue instance but cause the Uncaught TypeError when placed inside a Vue component?

My project has the Vue components, each in a component file and included like this:

<template>
    <div class="song-table">
        <song-modal-form></song-modal-form>
        <div class="table-header d-flex justify-content-between align-items-center mt-3">
            <form id="search" class="">
                Search <input name="query" v-model="filterKey"> 
            </form>
 ....
html continues

<script>
    import SongModalForm from './SongModalForm.vue';

    export default {

        components: {
            SongModalForm
        },
 ....
        methods: {
            showAddSongModal() {
                    console.log('HELP!');
                    $('#addSongModal').modal('show');
            },
  ....
</script>

This Pen shows the scenario, a parent component calling the child component with the modal.

The pen works, but in my actual project $('#addSongModal').modal('show'); is only working from the console and not from the component: enter image description here

2
Can you demonstrate the problem in a fiddle or codepen?Bert
What is it you're putting in the component? The button? The modal? Both?Bert
Both. Here is the component version so far: codepen.io/stwilson/pen/bqEoXLSTWilson
I see the problem.Bert

2 Answers

2
votes

I am using Laravel 5.4.14 framework in this project. Using webpack, I was mixing together .js files like this:

  • .js files required site-wide (JQuery, Bootstrap, Vue, et al) into one app.js

  • backend-specific .js files like my Vue instance and specialized scripts into backend.js

app.js had only the following one line to require bootstrap.js:

require('./bootstrap');

bootstrap.js required (JQuery, Bootstrap, Vue, et al).

backend.js looked something like this:

import SpecialComponent from './components/SpecialComponent.vue';
import LoginModal from './components/LoginModal.vue';
import RegisterModal from './components/RegisterModal.vue';
import SongTable from './components/SongTable.vue';

Vue.config.ignoredElements = [
  'wave'
];

const app = new Vue( {
    el: '#app-backend',

    components: {
        SpecialComponent ,
        LoginModal,
        RegisterModal,
        SongTable
    },

    data: {
        currentPath: window.location.pathname
    },
});

Then for a backend page, the html called the files like this:

<script src="js/app.js"></script>
<script src="js/backend.js"></script>

That DID NOT WORK.

Once require('./bootstrap'); was added to backend.js and I dropped app.js, the Uncaught TypeError went away.

1
votes

In components, you can only have one root element in your template. What you need to do is wrap your button and modal in a single div (or some other element) and your component will work.

Change your template to this in your failing codepen.

<div>
  <!-- Button trigger modal -->
  <button type="button" class="btn btn-primary mt-3 ml-3" @click="showAddSongModal()">
    Launch demo modal
  </button>

  <!-- Modal -->
  <div class="modal fade" id="addSongModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body" v-text="message"></div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div>
    </div>
  </div>
</div>

Working version.