3

I have a custom input where I recieve a value prop and emit a input event on the input event. I can use this custom input without problems with a model, now I'm creating a custom password input that I initialize as a custom input but I can't bind the model using value and input event handlers (passing them to the custom input). How can I approach this?

Custom Input:

  • My program model > custom input (value and input event handler) : works
  • My program model > custom password (value and input event handler) > custom input: doesn't work.

Code:

Input.vue:

<template>
    <div class="form-group">

      <label for="" v-if="typeof label !== 'undefined'">{{ label }}</label>

      <!-- GROUP  -->
      <template v-if="isGroup">
        <div class="input-group">
          <!-- PREPEND  -->
          <div v-if="hasPrepend" class="input-group-prepend"
              :class="{'inside bg-transparent' : prependInside, 'pointer': prependPointer}"
              @click="clickPrepend">

            <span class="input-group-text"
                  :class="{'bg-transparent' : prependInside}">

              <i  aria-hidden="true"
                  v-if="prependType === 'icon'"
                  :class="'fa fa-' + prependContent"></i>

              <template v-if="prependType === 'text'">{{ prependContent }}</template>
            </span>

          </div>

          <!-- INPUT  -->
          <input  class="form-control"
              :type="type"
              :class="generatedInputClass"
              :readonly="readonly"
              :disabled="disabled"
              :value="value"
              @input="inputEvent"
              @change="onChange">

          <!-- APPEND  -->
          <div v-if="hasAppend" class="input-group-append"
              :class="{'inside bg-transparent' : appendInside, 'pointer': appendPointer}"
              @click="clickAppend">

            <span class="input-group-text"
                  :class="{'bg-transparent' : appendInside}">

              <i  aria-hidden="true"
                  v-if="appendType === 'icon'"
                  :class="'fa fa-' + appendContent"></i>

              <template v-if="appendType === 'text'">{{ appendContent }}</template>

            </span>

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

      <!-- INPUT  -->
      <template v-else>
        <input  class="form-control"
              :type="type"
              :class="generatedInputClass"
              :readonly="readonly"
              :disabled="disabled"
              :value="value"

              @input="inputEvent"
              @change="onChange"
              >
      </template>

      <small  class="form-text"
              v-if="typeof helpText !== 'undefined'"
              :class="generatedHelperClass">
        {{ helpText }}
      </small>

    </div>
</template>

<script>
export default {
  name: 'InputGroup',
  props: {
    value: String,
    label: String,
    helpText: String,
    size: String,
    prependContent: String,
    appendContent: String,
    prependType: {
      type: String,
      default: 'icon',
    },
    appendType: {
      type: String,
      default: 'icon',
    },
    prependInside: {
      type: Boolean,
      default: false,
    },
    appendInside: {
      type: Boolean,
      default: false,
    },
    prependPointer: {
      type: Boolean,
      default: false,
    },
    appendPointer: {
      type: Boolean,
      default: false,
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    type: {
      type: String,
      default: 'text',
    },
    valid: {
      type: Boolean,
      default: null,
    },
  },
  watch: {
    valid() {

    },
  },
  computed: {
    isGroup() {
      return this.hasPrepend || this.hasAppend;
    },
    hasPrepend() {
      return typeof this.prependContent !== 'undefined';
    },
    hasAppend() {
      return typeof this.appendContent !== 'undefined';
    },
    generatedInputClass() {
      const size = typeof this.size !== 'undefined' ? `form-control-${this.size}` : '';
      let valid = '';
      if (this.valid !== null) {
        valid = this.valid ? 'is-valid' : 'is-invalid';
      }
      return `${size} ${valid}`;
    },
    generatedHelperClass() {
      let valid = 'text-muted';
      if (this.valid !== null) {
        valid = this.valid ? 'valid-feedback' : 'invalid-feedback';
      }
      return `${valid}`;
    },
  },
  methods: {
    inputEvent(e) {
      this.$emit('input', e.target.value);
    },
    clickPrepend(e) {
      this.$emit('click-prepend', e);
    },
    clickAppend(e) {
      this.$emit('click-append', e);
    },
    onChange(e) {
      this.$emit('change', this.value, e);
    },
  },
};
</script>

Password.vue:

<template>
<div>

  <app-input
              :label="label"
              :type="type"
              prepend-content="lock"
              :append-content="passwordIcon"
              :append-inside="true"
              :append-pointer="true"
              @click-append="tooglePassword"
              :value="value"
              @input="inputEvent">
  </app-input>
</div>
</template>

<script>
import Input from './Input';

export default {
  name: 'Password',
  components: {
    appInput: Input,
  },
  props: {
    value: String,
    label: {
      type: String,
      default: 'Contraseña',
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    valid: {
      type: Boolean,
      default: null,
    },
  },
  data() {
    return {
      pass: '',
      type: 'password',
    };
  },
  computed: {
    passwordIcon() {
      return this.type === 'password' ? 'eye' : 'eye-slash';
    },
  },
  methods: {
    tooglePassword() {
      this.type = this.type === 'password' ? 'text' : 'password';
    },
    inputEvent(e) {
      this.$emit('input', e.target.value);
    },
  },
};
</script>

1 Answer 1

2

The thing is the input event your Password listens form app-input component, has as value the actual string value already, not the element (that you'd have to call e.target.value to get the string value)

In other words, in Password.vue, instead of:

inputEvent(e) {
  this.$emit('input', e.target.value);
},

Do:

inputEvent(e) {
  this.$emit('input', e);
},

CodeSandbox demo here.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, right now I figure it out after 1hour but thank you :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.