How to pass current value of form input to a Vue component prop?

Viewed 1019

I have an existing HTML signup form (built using Laravel) that works great. I'm trying to create a Vue component that I can drop in place to progressively enhance it with password-requirements checkboxes like this:

enter image description here

My question is, how do I pass the current password value into the props of the component? I think what I'm looking for is called a one-way binding, but I'm not sure. Read on.

Here is an extremely simplified version of my form:

<div id="app">
    <form>
        <input id="email" type="email" required>
        
        <input id="passwordInput" type="password" required>

        <password-requirements password="<How do I bind this to #passwordInput above?>" />
        
        <button type="submit">Submit</button>
    </form>
</div>

Here is how my Vue application instance is attached to the page and how the component is registered:

app.js

Vue.component('password-requirements', require('./components/PasswordRequirements.vue').default);

const app = new Vue({
    el: '#app'
});

...and here is a simplified version of my code for the custom component:

PasswordRequirements.vue

<template>
    <!-- template html goes here -->
</template>

<script>
    export default {
        data: function () {
            return {
                hasLength: false,
                hasLowercase: false,
                hasUppercase: false,
                hasNumberOrSymbol: false
            }
        },
        props: {
            password: {
                type: String
            }
        },
        methods: {
            checkPassword: function() {
                /* code to check password requirements goes here */
            }
        },
        mounted() {
            this.checkPassword();
        }
    }
</script>

Again, my question is how to pass the current password value to the props of the <password-requirements> component. I would like to turn this into a reusable component that I can quickly drop into other existing forms to progressively enhance them, without requiring major changes to the form.

Thanks!

2 Answers

Add a data property for your password in the root Vue instance and then bind it to your <input> and component

const app = new Vue({
  el: '#app',
  data: () => ({ password: '' }) 
});
<!-- bind the input value to your data property with v-model -->
<input id="passwordInput" type="password" v-model="password" required>

<!-- bind the password property to your component's prop -->
<password-requirements :password="password" />

In your component, you can then watch for changes and run your checkPassword method

watch: {
  password (val) {
    this.checkPassword()
  }
}

You can probably remove the mounted hook at this point too.

you can try this.

Vue.component('ps-rq', {
  template: '#p-c',
  props: ['password'],
  data: () => ({
    length: false,
    uppercase: false
  }),
  watch: {
    password: {
      handler(val) {
        this.lh(val)
      },
      immediate: true
    }
  },
  methods: {
    lh(val) {
       if (val.length < 8) {
        this.length = false
       } else {
        this.length = true
       }
    },
  }
})

new Vue({
  el: '#app',
  data: function() {
    return {
      password: ''
    }
  }
})
.active {
  color: green
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">

  <input type="password" v-model="password" />
  
  <br /><br />
  <ps-rq :password="password"></ps-rq>
  
</div>

<script type="text/x-template" id="p-c">
  <div>
    <span :class="{ 'active': length }">At least 8 character</span>
  </div>
</script>

Related