Vue.js: Button disappears when adding v-on:click - javascript

I'm using the example from https://v2.vuejs.org/v2/guide/events.html#Method-Event-Handlers
I want to hide a message in #content when the button is clicked, but I encountered weird problem: button element disappears when v-on:click contains anything. When I remove "switch" from it, button appears on page.
Also, my second question: Is this the proper way of showing/hiding things using Vuejs?
My code:
<div id="navigation">
<button v-on:click="switch">Switch</button>
</div>
<div id="content">
<p v-if="show">{{ message}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var content = new Vue({
el: '#content',
data: {
message: 'Hello Vue!',
show: true
}
});
var navigation = new Vue({
el: '#navigation',
data: {
},
methods: {
switch: function() {
content.show = !content.show;
}
}
});
</script>

switch is a reserved Javascript keyword, using another name such as toggle for the method will solve the problem.
var content = new Vue({
el: '#content',
data: {
message: 'Hello Vue!',
show: true
}
});
var navigation = new Vue({
el: '#navigation',
data: {},
methods: {
toggle: function() {
content.show = !content.show;
}
}
});
<script src="https://unpkg.com/vue#2.5.2/dist/vue.js"></script>
<div id="navigation">
<button v-on:click="toggle">Switch</button>
</div>
<div id="content">
<p v-if="show">{{ message}}</p>
</div>
As a side note, I strongly discourage the approach in this example. Vue instances should be isolated. Creating components is recommended and communication between them can happen via an event bus or vuex.

Related

V-if directive not dynamically updating on variable change

I'm trying to create a button in my program that toggles on a number of other things and removes itself once it's clicked. The relevant HTML is as follows:
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<list v-for="name in chosenNames" v-bind:name="name"></list>
</ul>
</div>
In this, the unordered list should be shown once the variable "showlists" is true and the button should be removed once "showlists" is true. My Vue app looks like this:
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
showlists = true;
}
}
})
Based on this, the "showlists" variable starts as false, and the program works as intended with the button showing and the list hidden. Once the button is clicked, the function runs and showlists is then set to true (I confirmed this in my troubleshooting efforts). However, once this occurs, the DOM does not dynamically update and instead just remains as it was at the start.
Sorry if this is something really basic, I'm very new to Vue and still trying to learn :)
Any and all help would be appreciated.
You have to use the "this" keyword in your "revel" method before showlists like this.showlists = true; variable in your "Vue" instance.
For example, you can write like as follows
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<list v-for="(name, index) in chosenNames" :name="name" :key="'list-'+index"></list>
</ul>
</div>
And for new "Vue" instance
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
this.showlists = true;
}
}
})
I hope that might solve the problem :)
your code has 4 bug:
v-bind is set element's attribute, not innerHTML
showlists need change to this.showlists
showlists = true; is always set to true
list isn't valid html tag, you need li
below is right code:
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<li v-for="name in chosenNames" v-html="name"></li>
</ul>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
this.showlists = !this.showlists;
}
}
})
</script>

Scroll down in vue in specific element

I am trying to scroll down on new appeared element in vue:
I have chat messages where I have two arrays:
data() {
return {
activeChats: [],
openedChats: [],
maxOpened: math.round(window.innerWidth / 300),
}
}
When I get new message and the conversation is not in active and opened arrays I add to both and it appears on screen because I used v-for on both arrays.
This everything works but I am not sure how to scroll down on div when new chat appears, I tried using refs but had no luck:
<div class="chat" v-for="chat in openedChats" ref="chat-{chat.id}"></div>
Or even just chat testing with one chat opened..
And inside axios then() after success I said:
this.$refs.chat['-'+response.data.id].scrollTo(9999999,99999999);
or
this.$refs.chat['-'+response.data.id].scrollTop = 99999999;
or
this.$refs.chat.scrollTo(9999999,99999999);
or
this.$refs.chat.scrollTop = 99999999;
And neither worked...
Any help ? :D
Can it be done without additional library, I need no animatios just to appear at the bottom of the element...
Thanks
See this example:
https://jsfiddle.net/eywraw8t/430100/
Use "watch" (https://v2.vuejs.org/v2/guide/computed.html) to detect changes in the message array (either from ajax or simply a button like in the example).
Set the id (or you can use ref if you prefer) based on the index of the message.
Then scroll to the last element in your array (get the last one via array.length).
new Vue({
el: "#app",
data: {
messages: [
{ id: 1, text: 'message' },
],
},
watch:
{
messages: function() {
let id = this.messages.length;
//takes a bit for dom to actually update
setTimeout(function() {
document.getElementById('message-' + id).scrollIntoView();
}, 100);
},
},
methods: {
addMessage: function(){
let id = this.messages.length + 1;
this.messages.push({ id: id, text: 'message'});
}
}
})
<div id="app">
<button v-on:click="addMessage()" style="position:fixed">
Add message
</button>
<div class="message" v-for="message in messages" :id="'message-' + message.id">
{{message.text}} {{ message.id}}
</div>
</div>

vue2 flatpickr directive approach not working on mobile

I want to use a simple directive to use flatpickr with vue.js, like the author suggest here:
import Flatpickr from "flatpickr";
import Vue from "vue";
// <input type="text" v-flatpickr="{'enableTime': true}"
Vue.directive("flatpickr", {
bind: (el, binding) => {
el._flatpickr = new Flatpickr(el, binding.value);
},
unbind: el => el._flatpickr.destroy()
});
I created a simple fiddle to see if this works.
On the desktop it's all fine, but when switching to mobile-mode (via chrome dev tools) and press "run" the needed input isn't created. Only the hidden input is created (see via inspect).
Anyone knows what this could cause this?
try {
self.input.parentNode.insertBefore(self.mobileInput, self.input.nextSibling);
} catch (e) {
//
}
self.input.parentNode === null
It also returns null if the node has just been created and is not yet attached to the tree.
Use inserted instead bind
Vue.component('greeting', {
template: '<div><input type="text" v-flatpickr="{}" /></div>'
});
Vue.directive('flatpickr', {
inserted: (el, binding) => {
el._flatpickr = new flatpickr(el, binding.value)
},
unbind: el => el._flatpickr.destroy()
})
var vm = new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<script src="https://cdn.rawgit.com/chmln/flatpickr/v3.0.5-1/dist/flatpickr.js"></script>
<link href="https://cdn.rawgit.com/chmln/flatpickr/v3.0.5-1/dist/flatpickr.css" rel="stylesheet"/>
<div id="app">
<greeting></greeting>
</div>

How i can add click handler function to dynamically link in Vue?

Here in Vue component I receive dynamically message from server:
module.exports = {
data() {
return: { windowText: '' }
},
methods: {
showCancelEntrieWindow(){
this.$http.post('/page', {'number' : '123'})
.then(response => {
responseText = response.data.message;
this.windowText = responseText.replace(
new RegExp("class='action'", 'g'),
'v-on:click="myclick"'
);
});
},
myclick(){
console.log('clicked!');
}
}
};
Message have a link with class="action".
As example:
response.data.message = 'Some text... <a class="action" href="/test">test</a>';
In template:
<div v-html="windowText"></div>
How I can add some click handler function to this link?
I am trying to edit response.data.message with replace function like this:
this.windowText = responseText.replace(
new RegExp("class='action'", 'g'),
'v-on:click.stop="myclick"'
);
But it does not work.
Please help me.
And ofcourse, I can't edit response.data.message.
v-html will not compile the template, so replacing the class with the Vue directive will not do anything.
You can, however, use a native event listener.
new Vue({
el: "#app",
data:{
windowText: null,
someValueSetOnClick: null
},
methods:{
onHtmlClick(event){
// Check to make sure this is from our v-html because
// we don't want to handle clicks from other things in
// the Vue
if (!event.target.classList.contains("action"))
return;
event.stopPropagation();
event.preventDefault();
this.someValueSetOnClick = "Clicked";
}
},
mounted(){
this.windowText = 'Some text... <a class="action" href="/test">test</a>'
// Add a native event listener to the Vue element.
this.$el.addEventListener("click", this.onHtmlClick)
}
})
Example.

Get the calling element with vue.js

I want to get the calling html element in vue.js to modify it via jQuery. For now I give every element the class name + the index and call it via jQuery afterwards, but this looks like a crazy hack.
What I want to do:
new Vue({
el: "#app",
data: {
testFunction : function(element) {
$(element).doSomethingWithIt(); //do something with the calling element
}
}
});
This is the calling element:
<div v-on:click="testFunction(???)">Test</div>
What can I pass into the function to get the div-element or is there another way to achieve this?
You could get the element from the event like this:
new Vue({
el: "#app",
methods: {
testFunction : function(event) {
$(event.target).doSomethingWithIt();
}
}
});
And then:
<div v-on:click="testFunction">Test</div>
Or (if you want to pass another parameter):
<div v-on:click="testFunction($event)">Test</div>
[demo]
Youre doing it the wrong way.
new Vue({
el: "#app",
data: {
testFunction : function(element) {
$(element).doSomethingWithIt(); //do something with the calling element
}
}
});
data is the state or storage of data for your app.
you need to create methods object for your methods
new Vue({
el: "#app",
data: {
},
methods: {
testFunction : function(element) {
$(element).doSomethingWithIt(); //do something with the calling element
}
}
});
You want v-el to be able to run jQuery on it. For example:
<div v-on:click="testFunction" v-el:my-element>Test</div>
then:
// as noted by #vistajess
// your function should be in the methods object
// not the data object
methods: {
testFunction : function() {
$(this.$els.myElement).doSomethingWithIt();
}
}

Categories