question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Correct way to wrap an input?

See original GitHub issue

Versions:

  • VueJs: 2.5.2
  • Vee-Validate: 2.0.0-rc.26

Description:

I’ve tried many ways to wrap an <input> with support for v-model and v-validate. The only way I found is:

<template>
  <div>
    <label>{{label}}</label>
    <input type="text" v-model="innerValue" :name="name" v-validate="constraints">
    <template v-if="constraints !== ''">
      <span class="validation-status validation-status--invalid" v-if="errors.has(name)">❌</span>
      <span class="validation-status validation-status--valid" v-else>✅</span>
    </template>
  </div>
</template>

<script>
export default {
  props: {
    name: {
      required: true
    },
    value: {
      required: true
    },
    label: String,
    constraints: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      innerValue: null
    }
  },
  created () {
    this.innerValue = this.value
  },
  watch: {
    innerValue (newVal) {
      this.$emit('input', newVal)
    },
    value (newVal) {
      this.innerValue = newVal
    }
  }
}
</script>

Any other way would cause errors from vee-validate.

This works fine but it looks like a lot of code. Is there a better way to create such a component ?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
logaretmcommented, Jan 9, 2018

There is no “correct” way to do it, but I generally prefer to create input components that “work” with vee-validate, for example this is a component we use in some of our projects:

<template lang="pug">
  div
    label.add-mb1.u-block {{ label }}
    .input.is-rounded.add-mb2(:class="{ 'has-error': error, 'is-large': size === 'large', 'is-small': size === 'small' }")
      input(:type="type" ref="input" :name="name" :value="value" @blur="$emit('blur', $event.target.value)" @input="$emit('input', $event.target.value)" @change="$emit('change', $event.target.value)")
    span.input-message {{ error }}
</template>

<script>
export default {
  name: 'dk-input',
  $_veeValidate: {
    value () {
      return this.$refs.input.value;
    },
    name () {
      return this.name;
    },
    alias () {
      return this.label;
    },
    events: 'change|blur'
  },
  props: {
    label: String,
    name: {
      type: String,
      required: true
    },
    value: [Number, String],
    error: String,
    success: Boolean,
    size: {
      type: String,
      default: null,
      validator: (value) => {
        if (!value) return true;

        return ['small', 'large'].includes(value);
      }
    },
    type: {
      type: String,
      default: 'text',
      validator: (value) => {
        return ['url', 'text', 'tel', 'password', 'email', 'number'].includes(value);
      }
    }
  }
};
</script>

As you can see, there is no need for the innerValue here, but that means the component doesn’t know its state, and any errors or state must be passed to it like the error property:

              dk-input(
                name="firstName"
                label="First Name"
                data-vv-as="First Name"
                v-model="user.firstName"
                v-validate="'required'"
                :error="errors.first('firstName')"
              )

What you are doing is creating a “self-validating” component, which while is nice, could produce some state issues depending on the implementation like you’ve noticed.

I would like to add more improvements to the custom components validation, like the ability to inject the field state into it if its being validated by vee-validate which should make it easier to author components.

0reactions
chessydkcommented, Sep 2, 2018

This is my version. I disable the automatic validation (v-validate.disable) and makes a manual validation on blur and on input when the content has been validated and is invalid. I make it possible for the consumer to attach listeners or attributes at will, at the same time.

<template>
    <div>
        <label v-if="label">{{label}}</label>
        <input :class="{'border border-red': error}"
               v-validate.disable="constraints"
               :name="name"
               :value="value"
               @input="onInput"
               @blur="onBlur"
               v-on="listeners"
               v-bind="$attrs"
        >
        <span class="text-red" v-if="error">{{error}}</span>
    </div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';

@Component({
    name: 'input-field',
    inject: ['$validator'],
})
export default class InputField extends Vue {
    @Prop(String)
    public label!: string;

    @Prop({ type: String, required: true })
    public value!: string;

    @Prop({ type: String, required: true })
    public name!: string;

    @Prop(String)
    public constraints!: string;

    private get error() {
        return this.errors.first(this.name);
    }

    private get field() {
        return this.fields[this.name];
    }

    private onInput(ev) {
        this.$emit('input', ev.target.value);

        if (this.field.validated && this.field.invalid) {
            this.validate();
        }
    }

    private onBlur(ev) {
        this.$emit('blur', ev);

        if (this.field.dirty) {
            this.validate();
        }
    }

    private validate() {
        this.$validator.validate(this.name);
    }

    private get listeners() {
        const { input, blur, ...listeners } = this.$listeners;
        return listeners;
    }

    // From Vue-validate
    private errors!: any;

    // From Vue-validate
    private fields!: any;
}
</script>
Read more comments on GitHub >

github_iconTop Results From Across the Web

Wrapping text inside input type="text" element HTML/CSS
I have investigated using this technique, and it has some caveats. I love that it automatically sizes correctly, but it brings in a...
Read more >
Wrapping and breaking text - CSS: Cascading Style Sheets
Wrapping and breaking text. This guide explains the various ways in which overflowing text can be managed in CSS.
Read more >
HTML textarea wrap Attribute - W3Schools
The wrap attribute specifies how the text in a text area is to be wrapped when submitted in a form. Browser Support. Attribute....
Read more >
How to Wrap text in Html - Javatpoint
Step 2: Now, we have to use word-wrap property. So, we have to place the cursor between the head tag just after the...
Read more >
How to wrap text within an input field in a table? - Jotform
Hello, I am trying to find the best way to do this. There is a lot of information typed into each box within...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found