skip to Main Content

So I had an issue with svelte and google Recaptcha API.

My main HTML file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='utf-8'>
    <meta name='viewport' content='width=device-width,initial-scale=1'>

    <title>Svelte app</title>

    <link rel='icon' type='image/png' href='/favicon.png'>
    <link rel='stylesheet' href='/global.css'>
    <link rel='stylesheet' href='/build/bundle.css'>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Bitter:400,700">
    <link rel="stylesheet" href="/css/styles.min.css">

    <script defer src='/build/bundle.js'></script>
    <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>
</head>

<body>
</body>
</html>

My main.svelte

<script>
  import swal from "sweetalert";

  function verifyUser() {
    swal({
      title: "Please wait a minute!",
      text: "Do not close or exit this tab, we are currently verifying you...",
      icon: "info",
      backdrop: `rgba(0,0,0,1)`,
      showConfirmButton: false,
      allowOutsideClick: false,
      allowEscapeKey: false
    });
  }
</script>

<div>
  <div class="header-dark">
    <nav class="navbar navbar-dark navbar-expand-lg navigation-clean-search">
      <div class="container">
        <a class="navbar-brand" href="/">QSP Human Verification Module</a>
        <button class="navbar-toggler" data-toggle="collapse">
          <span class="sr-only">Toggle navigation</span>
          <span class="navbar-toggler-icon" />
        </button>
      </div>
    </nav>
    <div class="container hero">
      <div class="row">
        <div class="col-md-8 offset-md-2">
          <h1 class="text-center">
            Please complete the Captcha challenge to continue to the server.
          </h1>

          <form action="" method="post">

            <div
              class="g-recaptcha"
              data-sitekey="key"
              data-callback={verifyUser}
             />
          </form>

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

Problem is that function just becomes string of itself and can’t be executed using just "verifyUser" orverifyUser()returnsReCAPTCHA couldn’t find user-provided function: verifyUser`

using {verifyUser} becomes string (for more https://prnt.sc/qhyc2w)

executing like that returns:

ReCAPTCHA couldn't find user-provided function: function verifyUser() {
        swal({
            title: "Please wait a minute!",
            text: "Do not close or exit this tab, we are currently verifying you...",
            icon: "info",
            backdrop: `rgba(0,0,0,1)`,
            showConfirmButton: false,
            allowOutsideClick: false,
            allowEscapeKey: false
        });
    }

rollup config

import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';

const production = !process.env.ROLLUP_WATCH;

export default {
    input: 'src/main.js',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            // enable run-time checks when not in production
            dev: !production,
            // we'll extract any component CSS out into
            // a separate file — better for performance
            css: css => {
                css.write('public/build/bundle.css');
            }
        }),

        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration —
        // consult the documentation for details:
        // https://github.com/rollup/plugins/tree/master/packages/commonjs
        resolve({
            browser: true,
            dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
        }),
        commonjs(),

        // In dev mode, call `npm run start` once
        // the bundle has been generated
        !production && serve(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};

function serve() {
    let started = false;

    return {
        writeBundle() {
            if (!started) {
                started = true;

                require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
                    stdio: ['ignore', 'inherit', 'inherit'],
                    shell: true
                });
            }
        }
    };
}

Any how to properly pass the function?

3

Answers


  1. im Rour- the guy from discord. I want to share solution here for others.

    <script>
    import { onMount, onDestroy } from 'svelte';
    
    function verifyUser() {/* your fun here */}
    
    onMount(() => {
      window.verifyUser = verifyUser;
    })
    
    onDestroy(() => {
      window.verifyUser = null;
    })
    </script>
    <!-- then pass the name of function 'verifyUser' just as string' -->
    <div class="g-recaptcha" data-sitekey="key" data-callback="verifyUser" />
    

    Thinking that data-callback is searching for name of global function, so we define verifyUser as global function in the browser by assign it to the window variable

    Login or Signup to reply.
  2. You can try svelte-recaptcha-v2 package on npm for a more straight forward experience.

    Repository

    https://github.com/basaran/svelte-recaptcha-v2

    Demo

    https://basaran.github.io/svelte-recaptcha-v2/

    P.S I’m the author of the package.

    Login or Signup to reply.
  3. If using TypeScript, you’ll need to define your function for the Window interface.

    global.d.ts

    declare interface Window {
      onSubmit: (token) => void,
    }
    

    RecaptchaButton.svelte

    <script lang="ts">
      import { createEventDispatcher, onMount, onDestroy } from 'svelte';
      import { variables } from '../../variables';
    
      const { recaptchaSiteKey } = variables;
      const dispatch = createEventDispatcher();
      type ButtonType = 'primary' | 'secondary';
      export let type: ButtonType = 'primary';
    
      function onSubmit(token) {
        dispatch('click', { token });
      }
    
      onMount(() => {
        window.onSubmit = onSubmit;
      });
    
      onDestroy(() => {
        window.onSubmit = null;
      });
    </script>
    
    <svelte:head>
      <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    </svelte:head>
    
    <form on:submit|preventDefault={onSubmit}>
      <button
        class="g-recaptcha {type}"
        data-sitekey={recaptchaSiteKey}
        data-callback="onSubmit"
        type="submit"
      >
        Submit
      </button>
    </form>
    
    <style>
      button {
        ...
      }
      ...
    </style>
    

    ContactForm.svelte

    <script>
      function handleSubmit(event) {
        console.log(event.detail.token);
        return;
      }
    </script>
    
    <RecaptchaButton on:click={handleSubmit} type="primary">Submit</ButtonRecaptcha>
    

    You should add an error handler to the Recaptcha button component if using something like the above, you can use the "data-error-callback" property on the buttton; set up the Window interface, mount and destroy the same as "onSubmit" but with "onError".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search