Does vue.js have boolean modifiers for events? - vue.js

Is it possible in vue.js to do something like #click.not.ctrl to specify the event should only fire on click where the ctrl modifier is not true?

There is no such option in Vue.js as far as I know.
You can use a custom directive in order to achieve it: https://jsfiddle.net/wostex/63t082p2/35/
<div id="app">
<button v-noctrl:click="sayHi">Say hi</button>
</div>
new Vue({
el: '#app',
directives: {
'noctrl': {
bind(el,binding,vnode) {
if (binding.arg === 'click') {
el.addEventListener(binding.arg, function(event) {
if (!event.ctrlKey) {
event.preventDefault();
binding.value.call(this);
}
});
}
}
}
},
methods: {
sayHi() {
console.log('Hi');
}
}
});

No, we currently don't have such a functionality.
You have check yourself in your callback method.

Related

Vuejs $emit doesnt work in some part of a function, and in other part works

I am using vuejs3 and trying to emit event from a child component.
child Component
<input type="button" v-if="edition_mode" #click="cancel()" class="btn btn-primary" value="Annuler">
[...]
cancel(){
if(this.new_sav){
this.$emit('test')
}else{
console.log('else')
this.$emit('test')
}
},
Parent Component
<div v-if="creation_form">
<h4>Ajout Nouveau Sav</h4>
<sav-form
:initial_data="null"
:li_product="li_product"
:new_sav="true"
:customer_id="data.customer.id"
#action="form_action"
#test="test()"/>
</div>
[...]
test(){
console.log('test emit works')
}
When cancel() is executed, in the if case $emit() works correctly, but in the else case, only 'else' is printed and $emit is not executed. What I am doing wrong here ?
I also have several buttons in child component, in the same div, that all call differents function but some function 'can' emit event and other can't.
I am not sure what issue you are facing but it is working fine in the below code snippet. Please have a look and let me know if any further clarification/discussion required.
Demo :
Vue.component('child', {
template: '<div><button #click="cancel()">Trigger emit event from child!</button></div>',
data() {
return {
isValid: true
}
},
methods: {
cancel: function() {
this.isValid = !this.isValid;
if (this.isValid) {
console.log('valid');
this.$emit('test');
} else {
console.log('not valid');
this.$emit('test')
}
}
}
});
var vm = new Vue({
el: '#app',
methods: {
getTestEvent() {
console.log('Emit event from child triggered!');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child #test="getTestEvent"></child>
</div>
I was facing the same issue.
I use Vuex to store authenticated status of the user and my mistake was to use v-if="isAuth" attribute in parent component and the child component set isAuth to false through the store so this.$emit() doesn't work anymore.
Parent Component:
<login-form #onLogin="onLoginHandler" v-if="!isAuth" />
Child Component:
methods: {
example() {
[...]
const response = await axios.post("/login", data);
if (response.status === 200) {
// under the hood isAuth is set to True;
this.$store.dispatch("SET_AUTH", true);
}
// Doesn't work anymore because the parent component v-if is now False.
this.$emit("onLogin", response.data);
}
}

In vuejs, how to pass the html element when click a element?

I want to change a button color when I click that button.
If at jquery, I might use $(this).
<button v-on:click="clicked($event)">Change my color</button>
in script
...
methods: {
clicked:function(event){
???
}
}
How can I use the element which I clicked?
You should think about states for that. Avoid thinking the jQuery way in these situations because it will make your component less reactive to its state.
You could have a class attached to the button that depends on the state of it. When clicked, you change the state and then it would change the class applied to it. Check out the example:
http://jsfiddle.net/taokbg7q/
<button :class="{clicked: btnClicked}" #click="clickBtn"> My Button </button>
// ...
data: {
btnClicked: false
},
methods: {
clickBtn() {
this.btnClicked = true
}
}
// ...
.clicked {
background-color: red;
}
you can use style and class as dynamicly:
<button v-on:click="clicked()" :style="{color:
myColor}">Change my color</button
data(){
return {
myColor: 'black'
}
}
methods: {
clicked (){
this.myColor = 'red';
}
}
Bind a dynamic inline style to button and change its value with an event handler.
Events handlers
Binding inline styles
HTML
<div id="app">
<button v-on:click="clicked" :style="{color: activeColor}">Change my color</button>
</div>
JavaScript
new Vue({
el: '#app',
data: {
activeColor: null
},
methods: {
clicked() {
this.activeColor = 'red'
}
}
});

How to implement dirty state in VueJs

I am new to VueJs and I am working on a form that I want to enable the Save button only when a change occurs at the model.
My initial thought is to compute a dirty function comparing the initial model with the current.
Note: This code is not tested, it's here just for an example.
var app = new Vue({
el: '#app',
data: {a:0, b:'', c:{c1:null, c2:0, c3:'test'}},
initialData: null,
mounted():{ initialData = JSON.parse(JSON.stringify(data));},
computed: {
isDirty: function () {
return JSON.stringify(data) === JSON.stringify(initialData)
}
}
});
Is there a better way of doing this or is there any improvement you could suggest on the above-mentioned code?
You can use the deep option of watch as shown in the manual
var app = new Vue({
el: '#app',
data:
{
model:
{
a:0,
b:'',
c:
{
c1:null,
c2:0,
c3:'test'
}
},
dirty: false
},
watch:
{
model:
{
handler(newVal, oldVal)
{
this.dirty = true;
},
deep: true
}
}
});
Borrowing from -- > https://stackoverflow.com/a/48579303/4050261
You can bind single onchange event on the parent container and benefit from the fact that change events bubble:
<div class="container" #change="someThingChanged()">
<input v-model="foo">
<input v-model="bar">
... etc.
</div>

Extending Vue Lifecycle Hooks

I have a special application where I would like to run a method on every component when it is mounted. So I could have the method as a global mixin or something and then simply do..
mounted(){
this.mySpecialMethod();
}
However, I was wondering if it is possible to simply extend Vues mounted hook so the method is always run on every component when it is mounted. I have not been able to find in info on this.
If you really want to have everything call your mounted hook, you can use a global mixin.
Below, we have the mixin myMixin that will log to console every time something is mounted or destroyed. When you run the example, you can see that every time the plus button is clicked, it runs both the component's mounted hook as well as the mixin's hook.
If you want to extend this so that it can be reusable as a library, you can create a plugin out of it.
const foo = {
template: "<div #click='onClick'>hello</div>",
mounted() {
console.log("Foo's mounted");
},
methods: {
onClick() {
console.log("click");
}
}
}
const myMixin = {
mounted() {
console.log("I've been mounted");
},
destroyed() {
console.log("I've been destroyed");
}
};
Vue.mixin(myMixin);
const app = new Vue({
el: "#app",
data() {
return {
foos: []
};
},
components: {
foo
},
methods: {
add() {
this.foos.push("fizz");
},
remove() {
this.foos.pop();
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<button #click="add()">+</button><button #click="remove()">-</button>
<ul>
<li v-for="f in foos">
<foo></foo>
</ul>
</div>

Get Vue component object (class) from component instance

Question
Given I am in component context, how do I get the component object? By component object I mean the object you get when you import Component from 'Component.vue'.
Current progress
Here's one possibility I found.
const component = {
methods: {
getComponent: () => this,
displayItem () {
console.log('this.getComponent()', this.getComponent()) // undefined
console.log('this', this) // component instance
console.log('component', component) // what I need (component object)
},
},
}
export default component
The downside though is that it kills IDE support.
I also checked this manually.
Ideal solution
The approximation to syntax I'd like to see: this.$component.
What's the point?
Instantiate components via :is="component".
Perform instance of check.
The closer you got is vm.$options:
Vue.component('some-comp', {
template: '<p>{{ message }}</p>',
props: {name: String},
data() {
return {
message: 'Open the console!'
}
},
computed: {
example() {
return this.message.toUpperCase();
}
},
watch: {
message() {
console.log('watcher triggered');
}
},
mounted() {
console.log(this.$options);
console.dir(this.$options.__proto__);
}
});
new Vue({
el: '#app'
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<some-comp :name="'Alice'"></some-comp>
</div>
But it seems what you want is constructor:
Vue.component('aaa-aaa', {
template: '<div>AAA component</div>'
})
Vue.component('bbb-bbb', {
template: '<div>BBB component</div>'
})
new Vue({
el: '#app',
mounted() {
console.log(this.$refs.a1);
console.log(this.$refs.a1.constructor);
console.log(this.$refs.b1);
console.log(this.$refs.b1.constructor);
console.log('a1 a2', this.$refs.a1.constructor === this.$refs.a2.constructor)
console.log('a1 b1', this.$refs.a1.constructor === this.$refs.b1.constructor)
console.log('b1 b2', this.$refs.b1.constructor === this.$refs.b2.constructor)
console.log('b2 a2', this.$refs.b2.constructor === this.$refs.a2.constructor)
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<aaa-aaa ref="a1"></aaa-aaa>
<aaa-aaa ref="a2"></aaa-aaa>
<bbb-bbb ref="b1"></bbb-bbb>
<bbb-bbb ref="b2"></bbb-bbb>
</div>