htmlvue.jsvuejs3

Vue 3 capture button click within html and call function


I've been converting my Vue3 app to smaller SFCs and I'm struggling to capture the click event on a button within the html page.

Before, I had my component with a template, but I've moved the template out of the component and into my webpage.

The problem is when I click the button, nothing happens. No error so it's like it doesn't know where to call the function.

index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App</title>
    <script type="importmap">
      {
        "imports": {
          "vue": "https://unpkg.com/vue@3.2.37/dist/vue.esm-browser.prod.js",
          "axios": "https://cdn.jsdelivr.net/npm/@bundled-es-modules/axios@0.27.2/axios.min.js",
          "vue-demi": "https://cdn.jsdelivr.net/npm/vue-demi@0.14.10/+esm",
          "vuelidatecore": "https://cdn.jsdelivr.net/npm/@vuelidate/core@2.0.3/+esm",
          "vuelidatevalidators": "https://cdn.jsdelivr.net/npm/@vuelidate/validators@2.0.4/+esm",
        }
      }
  </script>

  <!-- <script defer type="module" src="./bootstrap.js"></script> -->
  <link href="https://cdn.jsdelivr.net/npm/sweetalert2@11.15.10/dist/sweetalert2.min.css" rel="stylesheet">
  </head>
  <body>
    <div id="newsletter-form">
      <div class="input-group mb-3">
        <input type="text" class="form-control text-white bg-transparent" placeholder="Enter your email" v-model="state.email" />
        <div class="input-group-append">
          <button class="btn btn-primary rounded-top-right-0" type="button" id="button-addon2" @click="recaptcha">Subscribe</button>
        </div>
      </div>
    </div>
    <script type="module">
      import { createApp } from 'vue'
      import NewsletterForm from './newsletter-form.js'

      createApp(NewsletterForm).mount('#newsletter-form')
    </script>
  </body>
</html>

NewsletterForm

import { reactive } from 'vue'
import axios from 'axios';
import { useVuelidate } from 'vuelidatecore'
import { required, email, maxLength } from 'vuelidatevalidators'

axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

export default {
  setup () {
    const state = reactive({
      email: ''
    })
    const rules = {
      email: { required, email, maxLength } // Matches state.contact.email
    }

    const v$ = useVuelidate(rules, state)

    const recaptcha = async () => {
      // Validate the form fields
      const result = await v$.value.$validate()
      if (!result) {
        alert('sdfgsdg');
        
        return
      }
    }

    return { state, v$ }
  },
  template: '#newsletter-form'
}

Solution

  • Not sure exactly about the Vuelidate part, but this code looks like it's working well.

    index.html

    <!DOCTYPE html>
    <html lang="">
    
    <head>
      <meta charset="UTF-8">
      <link rel="icon" href="/favicon.ico">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Vite App</title>
      <script type="importmap">
          {
            "imports": {
              "vue": "https://unpkg.com/vue@3.2.37/dist/vue.esm-browser.prod.js",
              "axios": "https://cdn.jsdelivr.net/npm/@bundled-es-modules/axios@0.27.2/axios.min.js",
              "vue-demi": "https://cdn.jsdelivr.net/npm/vue-demi@0.14.10/+esm",
              "vuelidatecore": "https://cdn.jsdelivr.net/npm/@vuelidate/core@2.0.3/+esm",
              "vuelidatevalidators": "https://cdn.jsdelivr.net/npm/@vuelidate/validators@2.0.4/+esm"
            }
          }
      </script>
    
      <!-- <script defer type="module" src="./bootstrap.js"></script> -->
      <link href="https://cdn.jsdelivr.net/npm/sweetalert2@11.15.10/dist/sweetalert2.min.css" rel="stylesheet">
    </head>
    
    <body>
      <div id="newsletter-form">
        <div class="input-group mb-3">
          <input type="text" class="form-control text-white bg-transparent" placeholder="Enter your email"
            v-model="state.email" />
          <div class="input-group-append">
            <button class="btn btn-primary rounded-top-right-0" type="button" id="button-addon2"
              @click="recaptcha">Subscribe</button>
    
            <div>Email: {{ state.email }}</div>
          </div>
        </div>
      </div>
      <script type="module">
        import { createApp } from 'vue'
        import NewsletterForm from './newsletter-form.js'
    
        createApp(NewsletterForm).mount('#newsletter-form')
      </script>
    </body>
    
    </html>
    

    newsletter-form.js

    import { reactive } from 'vue'
    import axios from 'axios';
    import { useVuelidate } from 'vuelidatecore'
    import { required, email, maxLength } from 'vuelidatevalidators'
    
    axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    
    
    export default {
      setup() {
        const state = reactive({
          email: ''
        })
        const rules = {
          email: { required, email, maxLength: maxLength(20) } // Matches state.contact.email
        }
    
        const v$ = useVuelidate(rules, state)
    
        const recaptcha = async () => {
          console.log('works here 👍🏻')
          // Validate the form fields
          const result = await v$.value.$validate()
          console.log('result', result)
        }
    
        return { state, recaptcha, v$ }
      }
    }
    

    The few changes I applied:


    Few notes: