Mass chain handler in Vue2 - vuejs2

I have a component (Vue2) with several buttons. After processing every button's #click, I need to call a method.
How can I do it without adding a call into each #click? Of course, all #clicks are different.
The only idea I see is to create component for the button, maybe there are better solutions?

Just use single handler for all #click events and pass the handler function for the specific button as an argument....
new Vue({
el: "#app",
methods: {
handleClick: function(handler) {
handler()
console.log("Common code executed")
},
button1: function() {
console.log("Button 1 clicked")
},
button2: function() {
console.log("Button 2 clicked")
},
button3: function(a) {
console.log(`Button 3 clicked (with additional argument: "${a}")`)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<button type="button" #click="handleClick(button1)">Button 1</button>
<button type="button" #click="handleClick(button2)">Button 2</button>
<button type="button" #click="handleClick(() => button3('hi!'))">Button 3 (with additional argument)</button>
</div>

Related

How to show a hidden div by clicking on another div (button) in Vue?

I am trying to show the loading div that's normally hidden after clicking a confirm button, even after changing the hidden value on click.
here is my code:
<div class="form-btns">
<button type="button" class="btns full-width" v-on:click="submitPhoneNumber(); isHidden = false">
{{t('confirmNumber')}}
</button>
<loader title="" v-if="!isHidden"></loader>
<button type="button" class="btns hyperlink">
{{t('accountRecovery')}}
</button>
</div>
data() {
return {
isHidden: true,
};
Your code is a little funky. Get rid of how you're trying to set the value directly in the template HTML and set it in your function in the methods. So your new code would be:
<div class="form-btns">
<button type="button" class="btns full-width" v-on:click="submitPhoneNumber()">
v {{t('confirmNumber')}}
</button>
<loader title="" v-if="!isHidden"></loader>
<button type="button" class="btns hyperlink">
{{t('accountRecovery')}}
</button>
</div>
Then in your methods just toggle the value like this:
data() {
return {
isHidden: true,
}
},
methods: {
submitPhoneNumber() {
this.isHidden = false; // I would probably rename this to isLoading and invert the logic
// Other stuff...
}
}
You should change the isHidden value inside the submitPhoneNumber, either as below, or with a dedicated function that you call in the first one.
let app = new Vue({
el: '#app',
data: {
isHidden: true
},
methods: {
submitPhoneNumber() {
this.isHidden = false;
// Simulate an API response after 3s to hide the loader
setTimeout(() => { this.isHidden = true; }, 3000);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" #click="submitPhoneNumber()">
Submit button
</button>
<p v-if="!isHidden">Loading...</p>
</div>

How to use keyboard buttons to manipulate numbers

How to click a button not only directly clicking mouse, but pressing a button on a keyboard (in this case, its a keyboard button with a value "1" that hasevent.key` = 1)???
new Vue({
el: "#app",
data: {
one: 1
},
methods: {
add(){
this.one++;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button v-on:1 #click="add">One</button>
<span> {{ one }}</span>
</div>
If you want to listen for global keyboard events you'll need to add the listener to the window, otherwise you need focus on element that the event is dispatched from.
It's just plain vanila js from there:
new Vue({
el: "#app",
data: {
one: 1
},
created() {
const component = this;
this.handler = function (e) {
e.keyCode == 38 && component.add()
e.keyCode == 40 && component.remove()
}
window.addEventListener('keyup', this.handler);
},
beforeDestroy() {
window.removeEventListener('keyup', this.handler);
},
methods: {
remove() {
this.one--;
},
add(){
this.one++;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="add">One</button>
<span> {{ one }}</span>
</div>
This is covered in the VueJS documentation.
From the documentation:
Key Modifiers
When listening for keyboard events, we often need to check for
specific keys. Vue allows adding key modifiers for v-on when listening
for key events:
<!-- only call `vm.submit()` when the `key` is `Enter` --> <input
v-on:keyup.enter="submit">
You can directly use any valid key names exposed via KeyboardEvent.key
as modifiers by converting them to kebab-case.
<input v-on:keyup.page-down="onPageDown">
In the above example, the handler will only be called if $event.key is
equal to 'PageDown'.

Programmatically bind custom events for dynamic components in VueJS

In my vuejs app I use dynamic component in the following way:
<mycomponent>
<component ref="compRef" :is="myComponent" v-bind="myComponentProps"></component>
<div class="my-buttons">
<my-button label="Reset" #click="reset()"/>
</div>
</mycomponent >
myComponent is a prop on the parent component which hold the actual component to inject.
myComponentProps are also prop which holds the porps for the injected instance.
I would like to know how can I also dynamically bind listeners to the component - I have understand that I cannot send an object to v-on with multiple events.
I was thinking about adding it programatically however haven't found any info about how it can be done for Vue custom events (kind for addEventListener equivalent for custom events)
Any tip would be much appreciated!
With Vue 2.2+, you can programmatically add an event listener with $on(eventName, callback):
new Vue({
el: '#app',
created() {
const EVENTS = [
{name: 'my-event1', callback: () => console.log('event1')},
{name: 'my-event2', callback: () => console.log('event2')},
{name: 'my-event3', callback: () => console.log('event3')}
]
for (let e of EVENTS) {
this.$on(e.name, e.callback); // Add event listeners
}
// You can also bind multiple events to one callback
this.$on(['click', 'keyup'], e => { console.log('event', e) })
}
})
<script src="https://unpkg.com/vue#2.6.8/dist/vue.min.js"></script>
<div id="app">
<div>
<!-- v-on:EVENTNAME adds a listener for the event -->
<button v-on:click="$emit('my-event1')">Raise event1</button>
<button v-on:click="$emit('my-event2')">Raise event2</button>
<button v-on:click="$emit('my-event3')">Raise event3</button>
</div>
<div>
<!-- v-on shorthand: #EVENTNAME -->
<button #click="$emit('my-event1')">Raise event1</button>
<button #click="$emit('my-event2')">Raise event2</button>
<button #click="$emit('my-event3')">Raise event3</button>
</div>
</div>
With Vue 2.6+, you can add an event listener dynamically in the template:
new Vue({
el: '#app',
data: {
eventname: 'click',
},
methods: {
handler(e) {
console.log('click', e.target.innerText)
}
}
})
<script src="https://unpkg.com/vue#2.6.8/dist/vue.min.js"></script>
<div id="app">
<button #[eventname]="handler">Raise dynamic event</button>
<!-- Set dynamic key to null to remove event listener -->
<button #click="eventname = null">Unbind event</button>
</div>
You can also declaratively bind multiple event listeners with v-on="{event1: callback, event2: callback, ...}":
new Vue({
el: '#app',
methods: {
onClick() { console.log('click') },
onKeyUp(e) { console.log('keyup', e.keyCode) }
}
})
<script src="https://unpkg.com/vue#2.6.8/dist/vue.min.js"></script>
<div id="app">
<input type="text" placeholder="type here" v-on="{click: onClick, keyup: onKeyUp}">
</div>

How can I include Vue.js code inside a Popper.js pop-up div?

I have the following Popper.js popup in which I have a button on which I want to attach a Vue.js click event.
However, while the click event works outside the popup, it doesn't work instead the popup.
How can I get changeText() to work inside the popup as well?
https://jsfiddle.net/edwardtanguay/jxs5nmxs
HTML:
<div id="app">
<div>
Message: {{message}}
</div>
<div>
<button #click="changeText()">outside works</button>
</div>
<hr/>
<a href="#"
id="example"
class="btn btn-primary"
rel="popover"
data-original-title="Test Form"
data-content='
<div class="form-group">
<label for="exampleInputPassword1">Name</label>
<input type="text" class="form-control">
</div>
<button #click="changeText()" class="btn btn-success">Submit</button>
'>Fill out form</a>
</div>
JavaScript:
var vm = new Vue({
el: '#app',
data: function() {
return {
message: 'hello'
}
},
methods: {
changeText: function() {
alert('test');
}
}
});
$(function () {
$('#example').popover({html: true});
});
ADDENDUM:
Even if I load the popover as a mounted hook, it only works outside the popup but not inside: https://jsfiddle.net/edwardtanguay/3seu8Lbw
Nor does it work if I include the Vue.js HTML in a popper.js template parameter: https://jsfiddle.net/edwardtanguay/uaf5wjtn/
The reason it doesn't work is because popover injects it's own html dynamically and obviously Vue does not compile this template.
You'll have to use popover events to overcome this, it's a bit hacky but i don't see any other way:
var vm = new Vue({
el: '#app',
data: function() {
return {
message: 'hello'
}
},
methods: {
changeText: function() {
alert('test');
}
},
mounted: function() {
var self = this;
$('#example').popover({
html: true
})
.on('hidden.bs.popover', function() {
self.changeText()
}).parent().delegate('.btn-success', 'click', function() {
$('#example').popover('hide')
});
}
});
https://jsfiddle.net/vangj1uc/

VueJS - Swap component on click

In my application I have many buttons. When I press it the button I would like to load a template (that replaces the selected button):
Templates:
Vue.component('component-1', {...});
Vue.component('component-2', {...});
Buttons:
<div id="toReplace">
<button>Button1</button>
<button>Button2</button>
</div>
In this case, when I press Button1 the content of the div toReplace should be component-1.
Sure, each component should have a "close" button that will show the buttons again (in short, the div toReplace) on press.
You need to bind a variable to :is property. And change this variable on button click. Also you will need to combine it with some v-show condition. Like so:
<div id="toReplace">
<div :is="currentComponent"></div>
<div v-show="!currentComponent" v-for="component in componentsArray">
<button #click="swapComponent(component)">{{component}}</button>
</div>
</div>
<button #click="swapComponent(null)">Close</button>
new Vue({
el: 'body',
data: {
currentComponent: null,
componentsArray: ['foo', 'bar']
},
components: {
'foo': {
template: '<h1>Foo component</h1>'
},
'bar': {
template: '<h1>Bar component</h1>'
}
},
methods: {
swapComponent: function(component)
{
this.currentComponent = component;
}
}
});
Here is quick example:
http://jsbin.com/miwuduliyu/edit?html,js,console,output
You can use v-bind:is="CurrentComponent" and #click=ChangeComponent('SecondComponent'). The argument has to be a string. To use the <component/> make sure your ExampleComponent has a slot
<Template>
<div>
<ExampleComponent>
<component v-bind:is = "CurrentComponent"/>
</ExampleCompoent>
<button #click="ChangeComponent('SecondComponent')">
</button>
</div>
</template>
<script>
import ExampleComponent from '#/components/ExampleComponent.vue'
import SecondComponent from '#/components/SecontComponent.vue'
export default{
...
data(){
return{
CurrentComponet:null
}
}
methods:{
ChangeComponent(NewComponent){
this.CurrentComponent = NewComponent
}