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

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/

Related

vuejs target all anchor tag onclick

I want to call a method when any anchor tag clicked. It is not possible to define #click or v-on on all element.
<a href="#">link1<a>
<a href="#">link2<a>
<a href="#">link3<a>
<a href="#">link4<a>
<a href="#">link5<a>
on jquery I can do this
$('a').click(function(){
//........
});
How can I achieve it in vuejs
Note: I have 10+ components in my app & a tag is spread every where in components.
You could attach the click handler on the parent/container element, and detect the target/child element being clicked via the event.target:
new Vue({
el: '#app',
methods: {
clicked(e) {
const container = e.currentTarget; // FYI
const anchor = e.target;
console.log(`${anchor.innerHTML} was clicked!`);
}
}
})
Vue.config.devtools = false;
Vue.config.productionTip = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="container" #click="clicked">
Link #1
Link #2
Link #3
<!-- more anchor elements here -->
</div>
</div>
This doesn't seem like a great idea, BUT you can "watch" changes. In this case to the collection of links and then attach an event handler...
Note: I didn't test this, but it should get you in the right direction
var vm = new Vue({
el: '#example',
data: {
linkList
},
// update the items in linkList when the DOM is ready
mounted(){
this.linkList = document.getElementsByTagName('a');
},
// watch for changes to linkList and do something
watch: {
linkList: function(){
for( var i=0; i < linkList.length; i ++ ){
LinkList[i].onclick = linkAction;
}
}
},
methods: {
linkAction: function (event) {
alert(event.target.tagName)
}
},
})
Edit: After reading the comments regarding the goal, you should let vue-router handle transitions between sections. I assume you don't want to edit each component so look into Dynamic Transitions inside the router.
In this case, you would "watch" for changes to the $route data and do your action there:
watch: {
'$route' (to, from) {
// to & from are data in the route object telling you which components are being shown
const toPath = to.path;
function(){
// do some action
}
}
}
This would function regardless of the tag used to trigger the route...
Well, you can achieve it by defining the links under data and loop through the v-for directive
First Way
new Vue({
el: "#app",
data: {
links: [
{ link: "first Link" },
{ link: "second Link" },
{ link: "Third Link" },
{ link: "Fourth Link" }
]
},
methods: {
onAnchor: function(e){
console.log("Clicked on", e.target.innerHTML);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<p v-for="link in links">
{{link.link}}
</p>
</div>
Second way
Create a wrapper component for a and use the same throughout the application.
Vue.component('An', {
template: '#anchor',
props: ['link']
})
new Vue({
el: "#app",
data: function() {
return {
links: [
{ link: "first Link", text:'first Link' },
{ link: "second Link", text:'second Link' },
{ link: "Third Link", text:'third Link' },
{ link: "Fourth Link", text:'Fourth Link' }
]
}
},
methods: {
changeText(event) {
console.log(event)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Anchor</h2>
<p v-for="link in links">
<An :link="link" v-on:on-click="changeText($event)"></An>
</p>
</div>
<script type="text/x-template" id="anchor">
<p>
{{link.link}}
</p>
</script>
Hope this helps!

get two datepicker input values using one mounted function with vue

I'm trying to get two input values using one mounted function for the date picker. But not getting how do I do that?
Here is the code:
HTML:
<div id="app">
<form v-on:submit.prevent="saveFleetJob">
<input type="text" class="fleet-date" v-model="item.from">
<input type="text" class="fleet-date" v-model="item.to">
<button class="btn btn-primary">Click</button>
</form>
</div>
Vue code:
new Vue({
el: "#app",
data: {
item: {
from:'',
to:''
},
},
mounted() {
$(".fleet-date").datepicker().on(
"changeDate", () => {
this.item.from = $('.fleet-date').val()
}
);
},
methods: {
saveFleetJob() {
alert(JSON.stringify(this.item));
},
}
})
js fiddle demo link here
Any suggestions please?
As Sphinx pointed there is some context mess, but it's not the only issue.
See this updated fiddle: https://jsfiddle.net/pb91fk6o/
You have to add
elem.dispatchEvent(new Event('input'))
to make this work.
So mounted should look like:
mounted() {
$(".fleet-date")
.datepicker()
.on("changeDate", (e) => {
e.target.dispatchEvent(new Event('input'))
})
},
See this issue for more details: https://github.com/vuejs/vue/issues/2804

Vue instance's $on method is not work

I just created an event bus in the main.js file like this:
main.js
Vue.prototype.$bus = new Vue()
After that, I just wrote some code to test the event bus like this:
TestComponent
<template>
<div>
<div class="account-modal_form">
<form action="" #submit.prevent="formSubmit">
<div class="account-modal_form__group" :class="{ warning: errors.has('password') }">
<div class="account-modal_form__input">
<input name="password" :type="passwordType" placeholder="" class="width-316" v-validate="'required'" v-model="password">
<i class="account-modal_form__viewpass" #click="togglePassword"></i>
</div>
<span class="account-modal_form__warning" v-show="errors.has('password')">
{{ errors.first('password') }}
</span>
</div>
{{ errors }}
<div class="account-modal_form__group">
<button type="submit" class="btn btn--primary btn--large">next</button>
<button type="button" class="btn btn--default" #click="cancelAction">cancel</button>
</div>
</form>
</div>
</div>
</template>
<script>
import { API } from '#/api'
export default {
data() {
return {
passwordType: 'password',
password: ''
}
},
methods: {
created() {
this.$bus.$on('test', () => console.log('test'));
},
nextStep() {
this.$bus.$emit('test');
},
formSubmit() {
this.nextStep();
}
}
}
</script>
When I click submit button I want to submit form first and call nextstep to emit an event, but the $on event output nothing.
You're running $emit before $on, so when you fire the event there are no listeners at that point, and it's better to register your listeners on the component created life cycle event, otherwise whenever you run your test method you'll register a new listener:
Vue.prototype.$bus = new Vue();
Vue.component('spy-component', {
template: '<p>{{this.text}}</p>',
data() {
return {
text: '',
}
},
created() {
this.$bus.$on('sendOriginPassword', (text) => {
this.text = text;
});
}
})
Vue.component('test-component', {
template: '<button #click="test">Click me</button>',
created() {
this.$bus.$on('sendOriginPassword', () => {
console.log('I am listening event')
});
},
methods: {
test() {
this.$bus.$emit('sendOriginPassword', 'Can you hear me?');
}
}
});
new Vue({
el: "#app",
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<spy-component></spy-component>
<test-component></test-component>
</div>

How to handle getting new data even?

I have got Vue-JS app. After use click variable rasters_previews_list get new data. I would like to generate list with them. I can't understand which directive I should use to handle this even.
Here is my code:
var userContent = Vue.extend({
template: `
<div class="LayersMenuSectionContent" v-if="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li> // generate list here
<ul>
</div>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function()
{
},
methods:
{
}
});
Should I use v-on or v-if?
When rasters_previews_list is changed, list is autorendered in v-for.
new Vue({
el: '#app',
template: `
<div class="LayersMenuSectionContent" v-show="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li>
<ul>
</div>
<button #click="add">Add</button>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function(){ },
methods: {
add(){
this.rasters_previews_list.push({id: 'hello'},{id: 'world'});
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="app"></div>
Extra: You must use v-show instead of v-if for this case

Copy clicked image src to other element background attribute with Vue

Im loading images with Vue resource (ajax). How can I copy clicked image src attribute and use it in div background attribute?
You can copy on click element test with:
new Vue({
el: '#app',
data: { src: ""},
methods: {
copySRC: function(event){
this.src = event.target.src;
this.copyClipboard();
},
copyClipboard: function() {
this.$refs["input"].select();
document.execCommand("copy");
}
}
});
img,input {
display:block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<img
src="https://picsum.photos/100"
#click="copySRC"
title="click to copy in the input"
/>
<input
v-model="src"
ref="input"
#click="copyClipboard"
title="click to copy in clipboard"
/>
</div>
Answer:
https://jsfiddle.net/q7xcbuxd/32/
<div id="app">
Click on the image:<br/>
<img id="img" src="https://avatars3.githubusercontent.com/u/2885?v=3&s=96" v-on="click: copySrc">
<div>
{{src}}
</div>
</div>
var vue = new Vue({
el: '#app',
data: {
src: ""
},
methods: {
copySrc: function(img){
this.src = img.srcElement.src;
}
}
});