I have some text:
Hover me
on positioning the cursor over the text, I would like it to change to:
I'm being hovered
on moving the cursor off, the text should change back to:
Hover me
I can do this with CSS, but I can't figure out how to do it with Vue?
Something like this should work.. easiest if you use a computed property.
CodePen mirror: https://codepen.io/oze4/pen/XQapNP
new Vue({
el: "#app",
data: {
hover: false
},
computed: {
message() {
return this.hover === true ? "I'm being hovered" : "Hover me";
}
},
methods: {
handleHover(s){
this.hover = s;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<div id="app">
<p #mouseover="handleHover(true)" #mouseleave="handleHover(false)">
{{ message }}
</p>
</div>
You need to define the output you want and a boolean for the hover state, I've called it "hoover"
data: () => ({
hoover: false
}),
computed: {
tyext() {
if (this.hoover === false) {
return "Hover Me"
}
return "I'm being hovered"
}
}
Then in the template you can have event listeners to change the boolean.
<p #mouseenter="hoover = true" #mouseleave="hoover = false">{{ tyext }}</p>
You typically wouldn't have logic like this in your template and would instead call a function like this #mouseenter="changeHoover" and change the state but I showed this for brevity, which was kind of pointless as I keep banging on like this.
Related
I'm doing an internet-shop app in vue and when I add to cart certain products, I need to show a text, that will show ,that element is added to cart. But afer some time, I need to hide the text. How can I do that?
,when you click on Add to cart button,this text shows up.
added to cart!
In mounted I tried this:
mounted() {
setTimeout(()=>{
this.isAdded=false
},1000)
}
but nothing works, text still appears there
new Vue({
el: "#demo",
data() {
return {
isAdded: false
}
},
methods: {
add() {
this.isAdded = true
setTimeout(()=>{
this.isAdded = false
}, 2000);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<button #click="add">add</button>
<h1 v-if="isAdded">
added
</h1>
</div>
When a button is clicked I wish to push it's name to an array. When the button is not clicked I want to remove it's name from an array.
I know how to do this with an #click that pushes/splices the array.
I would like to know if there's a simple way of binding the clicks of the button to the array, just like how a checkbox works with v-model. I understand you cannot use v-model on a button but if we were to make the button it's own component and use v-model on that...
<custom-button v-model="myArray"></custom-button>
Is there a way to make this work?
I would create the structure for the custom-button components like:
...,
props: {
originalArray: {
required: true
}
},
data(){
return {
modifiedArray: this.originalArray.map(x => ({...x}))
}
},
methods: {
yourMethod()
{
//do your logic on the modifiedArray
this.$emit('changed',this.modifiedArray);
}
}
then you could use it like:
<custom-button :original-array="this.myArray" #changed="newArray => this.myArray = newArray" />
I would do it like this:
const CBtn = {
template: '#c-btn',
props: ['array', 'label'],
data(){
return {
ncTimeout: -1
}
},
computed:{
arr_proxy: {
get(){
// shallow copy to not modify parent array indices
return this.array.slice()
}
}
},
methods: {
update(){
this.notClicked()
if(!this.arr_proxy.includes(this.label))
this.$emit('update:array', this.arr_proxy.concat(this.label))
},
notClicked(){
clearTimeout(this.ncTimeout)
this.ncTimeout = setTimeout(()=>{
let index = this.arr_proxy.findIndex(v => v === this.label)
if(index>=0){
this.arr_proxy.splice(index, 1)
this.$emit('update:array', this.arr_proxy)
}
}, 1000)
}
}
}
new Vue({
components: {
CBtn
},
template: '#main',
data(){
return {arr: []}
}
}).$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template id="c-btn">
<button
#click="update"
v-on="$listeners"
v-bind="$attrs"
>
{{label}}
</button>
</template>
<template id="main">
<div>
<c-btn label="1" :array.sync="arr" ></c-btn>
<c-btn label="2" :array.sync="arr" ></c-btn>
<c-btn label="3" :array.sync="arr" ></c-btn>
{{arr}}
<div>
</template>
<div id="app"></div>
So yes you can use v-model with in model option defined value: [propName] and event: [eventName] or the .sync modifier with 'update:[propName]' event.
I'm looking to run a function when the state changes in my Vue app.
In my component I'm able to get the boolean state of isOpen. I'm looking to run a function that adds focus to my form input when the modal opens and isOpen is set to true. I've tried using a watcher but with no luck. I'm opening my modal by calling :class="{ 'is-open': search.isOpen }" in the html and showing it via css. Any help would be most appreciated.
data() {
return {
isFocussed: this.$store.state.search,
//checks the state of isOpen?
}
},
computed: {
search() { return this.$store.state.search },
},
watch: {
isFocussed() {
this.formfocus()
},
},
methods: {
formfocus() {
document.getElementById('search').focus()
},
please check my snippet which shows the good way to work in Vue.js, you can work with refs which is very helpful instead of document.getElementById()
new Vue({
el: '#app',
data: {
isOpen: false,
},
computed: {
},
watch: {
isOpen(){
if(this.isOpen){
this.$nextTick( function () {
this.formfocus();
}
);
}
}
},
methods: {
formfocus(){
this.$refs.search.focus();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<div id="app">
<button v-on:click="isOpen = !isOpen">show modal</button>
<div v-if="isOpen">
<input ref="search" type="text" placeholder="search">
</div>
</div>
EDIT: i have added a conditional if on the watch, i hope this solves the problem
I am not sure what your template looks like but here is how I set focus on a conditional element.
element
<input type="text" class="search-input" v-model="search" :class="{'collapsed-search': hideInput}" placeholder="Enter keyword" ref="search">
notice the ref="search" on the input.
here is the method when the input condition is true
toggleSearch() {
this.hideInput = !this.hideInput
this.search = ''
setTimeout(() => {
this.$refs.search.focus()
}, 1000)
}
this.$refs.search.focus() is called after the element has been fully created which is the purpose of the setTimeout
I have a <select>-element that has a data property bound to it using v-model in Vue.
Sometimes I want to change that value dynamically. I also have an event-listener attached to this element which is triggered on the change-event. See code example:
<template>
<div class="mySelector">
<select id="testSelect" v-model="mySelectModel"
#change="onChange($event)">
<template v-for="(item, index) in someList">
<option :class="['btn', 'btn-default', 'removing-button']" :value="index">{{item.name}}</option>
</template>
</select>
</div>
</template>
<script>
export default {
data() {
return {
mySelectModel: null
}
},
props: {
},
methods: {
customChange: function() {
this.mySelectModel = ... // some value we from somewhere else that is set dynamically on some condiftion
},
onChange: function (event) {
if (!event) return;
// DO SOMETHING THAT WE ONLY WANT TO DO ON A REAL CLICK
}
},
}
</script>
The problem I have is that when I change the data value mySelectModel dynamically, like in the customChange-method, the change event is also called, triggering the method onChange. I only want to do stuff in that method if it was really triggered by a real click, not when it was changed dynamically.
I can not find a way to distinguish between those cases when the change-event is triggered by a click or when it is just changed for some other reason. Any suggestions?
See vue-js-selected-doesnt-triggering-change-event-select-option, it appears that select does not trigger #change when v-model is updated by JS (only when the selected value is changed by user).
A directive can add the functionality
Vue.directive('binding-change', {
update: function (el, binding, vnode) {
const model = vnode.data.directives.find(d => d.name === 'model')
if (model) {
binding.value(model.value)
}
}
})
use like
<select id="testSelect"
v-binding-change="onChange"
v-model="mySelectModel"
#change="onChange($event)">
Not sure about the parameter to onChange - I'll give it a test.
Similar to this suggested solution, you can make a settable computed that you v-model in your widget:
The get function simply returns the data item
The set function does whatever you want a change in the widget to do, in addition to setting the data item
Other code can change the data item directly and will not execute the set code of the computed.
new Vue({
el: '#app',
data: {
values: ['one','two','three'],
selectedItem: 'two'
},
computed: {
wrappedSelectedItem: {
get() { return this.selectedItem; },
set(value) {
console.log("Changed in widget");
this.selectedItem = value;
}
}
},
methods: {
changeToThree() {
console.log("Stealth change!");
this.selectedItem = 'three';
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<select v-model="wrappedSelectedItem">
<option v-for="value in values" :value="value">{{value}}</option>
</select>
<button #click="changeToThree">Set to three</button>
</div>
I don't have much knowledge about child and parent component and i am just simply trying to change value in child then emit then value to parent so i can show somewhere, But it looks like not working, Not emiting the value.
This should change to : Hello from child
{{ message }} From Parent
Can anyone look this code and tell me what is mistake ?
Vue.component('child1', {
template: '<p #click="runMe">{{ display }}</p>',
props: ['display'],
data: {
display: ''
},
methods: {
runMe() {
this.display = "Hello from child"
this.$emit("changeMessage", this.display)
}
}
})
new Vue({
el: "#app",
data: {
message: "Hello 2"
},
methods: {
messageRun() {
this.message = "Change By"
}
}
})
.btnMain {
display: block;
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.2/vue.min.js"></script>
<div id="app">
<button #click="messageRun" class="btnMain">Click Here</button>
<child1 :display="message" #changeMessage="message = $event"></child1>
<hr>
{{ message }} From Parent
</div>
In your code you have this where you emit:
this.$emit("changeMessage", this.display)
Change to :
this.$emit("newmessage", this.display)
I mean use lower case single word, if you use camelCase vue convert it to change-message but this is not acceptable by attribute, I tried this on your code.
After change this do this :
<child1 :display="message" #newmessage="message = $event"></child1>