Vuejs keyup event trigger with keyCode and condition - vue.js

I wanted to bind an event on condition and trigger it only when the user enters a particular key, For example,
I want to bind the event when the value of the label equal to tags
onTagAdd($event, index) : {} }" v-model="value">
onTagAdd: function (oEvent, index){
if(oEvent.key === ";"){
//some code
}
}
It's working as expected.
Further, I wanted to trigger the event only when ; (virtual key code = 186) pressed, so I have tried below code
onTagAdd($event, index) : {} }" v-model="value">
It is not working. I have referred vue.js documentation But, haven't got any workaround.
How to do this?
Note: I have eliminated this approach as it's giving me an error in IE for $event. still looking for the solution if any which solves the problem and support the browser compatibility.

Try this out and tell me if it worked.
<input type="text" v-on:keyup.186="{ (label == 'Tags') ? $event => onTagAdd($event, index) : {} }" v-model="value">

maybe the inline style doesn't support keycode in event type(not sure),try this out:
<input type="text" v-on:keyup.186="onTagAdd($event,2)" v-model="value">
methods: {
onTagAdd(event,index){
// put your logic codes here
console.info('==')
console.info(event)
console.info(index)
}
}

This page was helpful for me in Vue3: https://v3-migration.vuejs.org/breaking-changes/keycode-modifiers.html
3.x Syntax#
Since KeyboardEvent.keyCode has been deprecated, it no longer makes sense for Vue 3 to continue supporting this as well. As a result, it is now recommended to use the kebab-case name for any key you want to use as a modifier.
<!-- Vue 3 Key Modifier on v-on -->
<input v-on:keyup.page-down="nextPage">
<!-- Matches both q and Q -->
<input v-on:keypress.q="quit">
As a result, this means that config.keyCodes is now also deprecated and will no longer be supported.
TLDR: in Vue 3 keycodes appear to be deprecated in favour of using kebab case.
For example, #keyup.186 would be #keyup.;

Related

Getting element (button) data attribute with vue3

I have the following html div. The {{ }} represent liquid syntax and it renders server side.
<div class="two columns">
<button
data-value='{{ value }}'
class="button-selection"
:class="selectionButtonClass($event)"
#click="selectionButton($event)"
>
<span class="text">{{ value }}</span>
</button>
</div>
In a vue 3 instance I have the following method in the same page.
selectionButtonClass(el) {
console.log('checking val');
console.log(el);
}
My goal is to set a conditional class in the selectionButton method but I can't get the element to get the data attribute. The above appears in the console log as undefined. However the #click does show the event obviously it's recognize the onclick but not the class method check.
$event is only available to event handlers. #click="selectionButton($event)" defines an inline event handler, while :class="selectionButtonClass($event)" is not an event handler.
To get the element, you need to add a ref attribute to the <button>:
<button
ref="selectionButton"
data-value='{{ value }}'
class="button-selection"
:class="selectionButtonClass($event)"
#click="selectionButton($event)"
>
And access it by this.$refs.selectionButton, assuming you are using the options API. However, the ref is available only after the component is mounted. Thus you need to handle the case where the ref is null.
More on template refs: https://vuejs.org/guide/essentials/template-refs.html
Since you are using server side rendering, I think it would be better to render the value as a parameter of the selectionButton function on the server side.

How to disable rule [plugin:vite:vue] Duplicate attribute

I have a Vue 3 app set up with Vite and Storybook.
I am trying to use two class attributes for a button, which I believe is perfectly valid:
<button
:id="id"
:type="type"
#click="onClick"
:class="classes"
:class="{
'bg-gray-100': disabled,
'cursor-not-allowed': disabled,
'inline-block': block,
'w-full': block,
}"
:disabled="disabled">{{ text }}<slot/></button>
Running the project, npm run storybook, gives me
[vite] Internal server error: Duplicate attribute.
Plugin: vite:vue
Where and how do I disable this rule?
In vue.js, you can't have two v-bind for the same attributes on one element.
In your case you are putting twice the classes elements wich results in the Duplicate attribute. error.
To solve your problem, I would recommand mergind your classes attributes using a computed properties with the other classes you are trying to add.
export default {
computed: {
mergedClasses(){
return {...this.classes,
'bg-gray-100': disabled,
'cursor-not-allowed': disabled,
'inline-block': block,
'w-full': block,
}
}
}
}
And use it in the template :
<button
:id="id"
:type="type"
#click="onClick"
:class="mergedClasses"
:class="{
'bg-gray-100': disabled,
'cursor-not-allowed': disabled,
'inline-block': block,
'w-full': block,
}"
:disabled="disabled">{{ text }}<slot/></button>

Vue : Custom parameter [duplicate]

I pass a parameter in v-on:input directives. If I don't pass it, I can access the event in the method. Is there any way I can still access the event when passing the parameter to the function? Note that I am using vue-router.
This is without passing the parameter. I can access the event object:
HTML
<input type="number" v-on:input="addToCart" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (event) {
// I need to access the element by using event.target
console.log('In addToCart')
console.log(event.target)
}
}
This is when passing the parameter. I can't access the event object:
HTML
<input type="number" v-on:input="addToCart(ticket.id)" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (id) {
// How can I access the element by using event
console.log('In addToCart')
console.log(id)
}
}
Here is a fiddle of the code, it should be good enough to replicate the problem that I am having:
https://jsfiddle.net/lookman/vdhwkrmq/
If you want to access event object as well as data passed, you have to pass event and ticket.id both as parameters, like following:
HTML
<input type="number" v-on:input="addToCart($event, ticket.id)" min="0" placeholder="0">
Javascript
methods: {
addToCart: function (event, id) {
// use event here as well as id
console.log('In addToCart')
console.log(id)
}
}
See working fiddle: https://jsfiddle.net/nee5nszL/
Edited: case with vue-router
In case you are using vue-router, you may have to use $event in your v-on:input method like following:
<input type="number" v-on:input="addToCart($event, num)" min="0" placeholder="0">
Here is working fiddle.
You can also do something like this...
<input #input="myHandler('foo', 'bar', ...arguments)">
Evan You himself recommended this technique in one post on Vue forum. In general some events may emit more than one argument. Also as documentation states internal variable $event is meant for passing original DOM event.
Depending on what arguments you need to pass, especially for custom event handlers, you can do something like this:
<div #customEvent='(arg1) => myCallback(arg1, arg2)'>Hello!</div>
I like this way of passing parameters because we can pass events and parameters both using an anonymous callback function.
<button v-on:click="(e)=>deleteHandler(e, args1)" > Click me </button>

Vue seems to be calling all custom directives more often than expected. Why, can this be avoided?

I'm only a few months into vue coming from an angularjs background.
I built my first custom directive and it's acting a little odd to me.
Vue.directive('silly',{
componentUpdated: function (el, binding, vnode) {
console.log("it was called");
}
});
and I place it on my form like this:
<form id="opt-cpmt-form" method="post" class="mri-grid mri-p-none">
<label for="one">name<input id="one" type="text" v-model="local.name" v-silly class="form-control"></label><br/>
<label for="two">phone<input v-isnumeric id="two" type="text" v-model="local.phone" class="form-control "></label><br/>
<label for="two">zip<input id="three" type="text" v-model="local.zip" class="form-control" ></label><br/>
</form>
It kinda works...the part that I didn't understand is that my v-silly directive is called when any of the other fields are updated too. It seems to be related to the model but I only want my directive called when the field changes.
Any ideas??
It's an expected behaviour as the component updates whenever a piece of its data object is updated. To not trigger the logic too many times, you can create an event listener when the directive is bound to its parent and then run the logic when a desired event happens.
Vue.directive('silly', {
bind(el) {
this.updateCallback = function(event) {
// Your logic
};
el.addEventListener('input', this.updateCallback);
},
unbind(el) {
el.removeEventListener('input', this.updateCallback);
}
});
In case you plan to listen to the changes of v-model directive, bear in mind that it uses different events based on what element it's bound to. You can read more about that topic in v-model documentation.
v-model internally uses different properties and emits different events for different input elements:
text and textarea elements use value property and input event;
checkbox and radiobutton inputs use checked property and change event;
select fields use value as a prop and change as an event.
Also, from my experience when it comes to the form validation; I've done it using the directives and regretted it afterwards. I found it best to create reusable functions and create the custom form validation for every form. See custom form validation for more.

How create a v-model modifier to a VueJS Component?

In VueJS there is some v-model modifies that pre-parse the binded value, for instance v-model.trim that removes whitespaces from the string.
How can I create my own modifier? for instance v-model.myparse
Today um using something like:
computed: {
name: {
get: function () { return parse(this._name);},
set: function (value) { _name = parse(value);}
}
What is very verbose.
I would it to be reusable to do something like:
<input v-model.myparse="name" name='n1'/>
<input v-model.myparse="name" name='n2'/>
<input v-model.myparse="name" name='n3'/>
<input v-model.myparse="name" name='n4'/>
computed properties with setters seems to do part of the work, but it is really useful with some few variables only, it becomes very verbose with a lot of properties.
First, adding adding a custom modified to v-model is under discussion but not yet implemented.
If it was implemented, you could extend the v-model and add a modifier to it.
Since that is not possible, you have a couple of options left, one of which is to use :value instead of v-model. Because v-model is just a syntactic sugar of following:
<input type="text" :value="message" #input="message = $event.target.value">
The above code is the same as:
<input type="text" v-model="message">
So, I suggest you replace the logic for the #input to something like this:
<input type="text" :value="message" #input="getModel">
Now, you can use a function to return a modified value as:
methods: {
getModel ($event) {
return $event.target.value.trim()
}
}
But all of what I mentioned can still be done with the v-model if you use a function.
Of course it goes without saying, you can create your own custom directive also.