Reputation: 13
I'm kind of new to Vue, so please correct me if I'm formulating the question in a wrong way.
Use Case:
I have a very simple form it contains a TextField "Name" and a Button "Create". When the user have written a name then I wish that the user can press "Enter" to create the entity.
Code and findings:
I followed the instructions on how to pass events to a input field from the page below
https://v2.vuejs.org/v2/guide/events.html
When I use a input field it works as expected. Like this <input @keyup.enter="createCollection" />
But we are using TextField in a component for various reasons and I cannot get it to work. I have tried to get it working by trying a lot of different things, but for simplicity I just mention how I do now(or think it should work.).
<FormValidatedText
:label-text="$t('COLLECTION_CREATE')"
:value="collection.name"
:min-length="3"
:max-length="30"
:required="true"
:input-id="'collection'"
:invalid="!formIsValid"
class="inline-form-field"
@input="collectionFormNameChanged($event)"
@validation="validCollectionName = $event"
@keyup.enter="createCollection()"
/>
Other information and code:
The Component
<template>
<div :class="{ invalid: touched && (valid === false || invalid === true) }">
<label class="small-label" :for="inputId">{{ labelText }}</label>
<input :id="inputId" type="text" class="field-value" :value="value" @input="onTextChange" @blur="isTouched" />
<ul v-if="touched && !valid" class="field-value-errors">
<li v-for="(error, index) in errors" :key="index">
{{ $t(error.message, { variable: error.variable }) }}
</li>
</ul>
</div>
</template>
<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator';
import ValidateTextMixin from '@/components/Form/ValidateTextMixin.vue';
@Component
export default class FormValidatedText extends Mixins(ValidateTextMixin) {}
</script>
The Mixin that the Component uses
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class ValidateTextMixin extends Vue {
@Prop({ default: '' }) value!: string;
@Prop({ required: true }) readonly inputId!: string;
@Prop({ required: true }) readonly labelText!: string;
@Prop({ default: false }) readonly required!: boolean;
@Prop({ default: false }) readonly invalid!: boolean;
@Prop() readonly minLength?: number;
@Prop() readonly maxLength?: number;
protected changed: boolean = false;
protected touched: boolean = false;
protected valid: boolean = false;
protected errors: any[] = [];
onTextChange($event: { target: HTMLInputElement }) {
this.isValid($event.target.value);
this.$emit('input', $event.target.value);
}
isValid(value: string) {
this.valid = true;
this.errors = [];
if (this.required && !value) {
this.valid = false;
this.errors.push({ message: 'REQUIRED_FIELD_ERROR' });
}
if (this.minLength && value.length < this.minLength) {
this.valid = false;
this.errors.push({
message: 'MINLENGTH_ERROR',
variable: this.minLength
});
}
if (this.maxLength && value.length > this.maxLength) {
this.valid = false;
this.errors.push({
message: 'MAXLENGTH_ERROR',
variable: this.maxLength
});
}
this.$emit('validation', this.valid);
}
isTouched() {
if (!this.touched) {
this.isValid(this.value);
}
this.touched = true;
}
}
</script>
Final implementation
Based on the answer from Ahmad Mobaraki. Please give him your vote if you think this is helpful =)
The component
<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator';
import ValidateTextMixin from '@/components/Form/ValidateTextMixin.vue';
@Component
export default class FormValidatedText extends Mixins(ValidateTextMixin) {
created() {
window.addEventListener('keyup', (event) => {
if (event.keyCode == 13) { // on enter
this.$emit('enterpressed');
}
});
}
}
</script>
And the usage of the Component
<FormValidatedText
:label-text="$t('COLLECTION_CREATE')"
:value="collection.name"
:min-length="3"
:max-length="30"
:required="true"
:input-id="'collection'"
:invalid="!formIsValid"
class="inline-form-field"
@input="collectionFormNameChanged($event)"
@validation="validCollectionName = $event"
@enterpressed="createCollection"
/>
Upvotes: 1
Views: 3822
Reputation: 8160
I don't think Vue support key
events on elements other than input
tag. To do this you have to register a custom event handler for your component, like this:
{
created: function () {
window.addEventListener('keyup', this.myMethod)
},
methods: {
myMethod: function () {
// stuff
}
}
}
So in your case, you should do something like this:
1- Register event in your component:
export default class FormValidatedText extends Mixins(ValidateTextMixin) {
created: function () {
window.addEventListener('keyup', (event) =>{
if (e.keyCode == 13) { // on enter
this.$emit('enterpressed')
}
})
},
}
2- Listen to it in the parent component:
<FormValidatedText
.
.
.
@enterpressed="createCollection()"
/>
Upvotes: 1