Accounts.loginWithPassword causes form to submit with vue sfc

Hi all, Im struggling with an issue in a custom accounts login page which I cant work out. I find that calling Accounts.loginWithPassword causes my form to be submitted even with evt.preventDetault() in the submit method. I want to stop submit so that can show an “authentication failed” message. I wonder if anyone can point me to the root cause and suggest a solution? I’ve created a minimal demo here: https://github.com/mattsouth/vue-accounts-demo

Hi,

I think the main issue is that in your main App.vue you have

  <b-spinner v-if="loading" />
  <div class="container" v-else>
    <authenticated v-if="currentUser" />
    <anonymous v-else />
  </div>
...
    loading() {
      return Meteor.loggingIn();
    }

This means that as soon as the login method is called, the spinner replaces your entire Anonymous.vue component (because Meteor.loggingIn() becomes true), which means the callback of that login method has no valid Vue instance.

Move that loading spinner into Anonymous.vue, and (for a better user experience) instead of making it replace the entire page, make it replace just the Submit button.

Also, here’s a few of other pointers of working with Vue:

  • Don’t mix jQuery with Vue - The whole point of Vue is binding your view with your data, so you don’t need jQuery to get and set input values - use v-model instead.
  • use arrow functions for callbacks: (error) => {} then you don’t need _this = this everywhere.
  • Don’t use HMR, run meteor with: NO_MHR=1 meteor

Also Meteor and Accounts are global, so don’t actually need to be imported anywhere.

Here’s my improved version of Anonymous.vue, but don’t forget to remove the spinner from App.vue:

Anonymous.vue
<template>
  <div class="row">
    <div class="col-8 offset-2">
      <b-card bg-variant="light" class="mt-5">
        <b-card-body>
          <div class="h5 text-center mb-0">User Login</div>
          <hr class="mt-2" />
          <b-alert v-model="showMessage" variant="danger" dismissible>
            <strong>Authentication failed</strong> Please check your username and password and retry.
          </b-alert>
          <div class="row">
            <div class="col-8 offset-2">
              <form role="form" @submit.prevent="signIn">
                <b-form-group>
                  <b-form-input v-model.trim="username" placeholder="Username or email address" />
                </b-form-group>
                <b-form-group>
                  <b-form-input v-model.trim="password" type="password" required placeholder="Password" />
                </b-form-group>
                <b-spinner v-if="loading" />
                <b-button v-else type="submit" variant="success">Submit</b-button>
              </form>
            </div>
          </div>
        </b-card-body>
      </b-card>
    </div>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      showMessage: false,
      username: '',
      password: '',
    };
  },
  meteor: {
    loading() {
      return Meteor.loggingIn();
    }
  },
  methods: {
    signIn() {
      this.showMessage = false; // in case it was previously true
      Meteor.loginWithPassword(this.username, this.password, (error) => {
        if (error) {
          this.showMessage = true;
        } else {
          this.username = this.password = ''
        }
      });
    }
  }
}
</script>

After making this change you can remove jQuery with

meteor remove jquery blaze-html-templates
meteor add static-html
meteor npm remove jquery
NO_HMR=1 meteor

thankyou @wildhart!

So I had inadvertently shot myself in the foot with my App.vue loading spinner and misdiagnosed what I was seeing as an erroneous form submit. Your suggestions dug me out of that hole and as a bonus I get to reduce my app payload (by removing some of blaze). I’ve updated my demo repository with your suggestions which completely hit the spot. Im much obliged. But I dont get the final point about HMR. I can see it suggested in the vue meteor documentation but I dont understand it. What does running NO_HMR=1 meteor actually do differently to running meteor?

Glad I could help!

I’m actually not sure about the NO_HMR, it might be outdated now based on an earlier bug which has been fixed.

If you’re keen to minimize bundle size, you should get into the habit of using dynamic import, it’s really easy with Vue. First add the package:

meteor add dynamic-import

Then change your App.vue to this:

<script>
/* import Authenticated from '/imports/ui/Authenticated'; // remove this line!  */
import Anonymous from '/imports/ui/Anonymous';
export default {
  components: {
    anonymous: Anonymous,
    authenticated: () => import ('/imports/ui/Authenticated'), /* don't load until needed! */
  },
  ...

Then your components for logged-in users will not be included in your initial bundle.