How can I select element Id with a function in Vue.js? - vue.js

I want to use the Id of the element in which I use the function as a parameter. Example:
<div
class="col-2 column-center"
id="myId"
#mouseover="aFunction(id)"
>
methods: {
aFunction(id){
alert(id);
}
}
But it doesn't work. How can I do it?

In another way, you can make your id attribute bind with the data property, like this :
<template>
<div class="col-2 column-center" v-bind:id="id" #mouseover="aFunction(id)">
test
</div>
</template>
<script>
export default {
name: 'Test',
data() {
return {
id: 'myId',
};
},
methods: {
aFunction(id) {
alert(id);
},
},
};
</script>

You can pass the event to the method and then get the id from event.target.id.
https://jsfiddle.net/tr0f2jpw/
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
methods: {
aFunction(event){
alert(event.target.id);
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div
class="col-2 column-center"
id="myId"
#mouseover="aFunction($event)"
>
some stuff
</div>
</div>

Related

vue reactivity in list with slot scoped component

Good afternoon!
I have a loop and inside each element I display a separate component that takes props and gives them through the slot. I can't figure out why when new elements are added the update hooks happen on the old ones?
Example:
have: 1 2 3
add: 4
log: created 4, updated 3, updated 2, updated 1
Why is this happening?
Vue.component('slot-component', {
inheritAttrs: false,
created() {
console.log('created', this._uid);
},
updated() {
console.log('updated', this._uid);
},
render(h) {
return this.$scopedSlots.default(this.$attrs);
}
})
new Vue({
el: '#app',
data() {
return {
list: []
}
},
methods: {
add() {
this.list.push({
title: 'some'
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<div id="app">
<div class="list">
<div
v-for="(item, n) in list"
:key="n"
class="list-item"
>
<slot-component
:title="item.title"
v-slot="props"
>
{{ props.title }}
</slot-component>
</div>
<button #click="add">add</button>
</div>
</div>
Update
Thanks to Raphael Rollet for clarifying that all array elements are updated when the array is changed globally. But then it is not entirely clear why this behavior behaves differently with a component that uses props
Pass and use props — not call updated
Vue.component('slot-component', {
props: ['title'],
created() {
console.log('created', this._uid);
},
updated() {
console.log('updated', this._uid);
},
template: `<div>{{ title }}</div>`
})
new Vue({
el: '#app',
data() {
return {
list: []
}
},
methods: {
add() {
this.list.push({ title: 'some' });
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<div id="app">
<div class="list">
<slot-component
v-for="(item, n) in list"
:key="n"
:title="item.title"
class="list-item"
>
</slot-component>
<button #click="add">add</button>
</div>
</div>
Pass and use props with slot — call updated
Vue.component('slot-component', {
props: ['title'],
created() {
console.log('created', this._uid);
},
updated() {
console.log('updated', this._uid);
},
template: `<div><slot>{{ title }}</slot></div>`
})
new Vue({
el: '#app',
data() {
return {
list: []
}
},
methods: {
add() {
this.list.push({ title: 'some' });
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<div id="app">
<div class="list">
<slot-component
v-for="(item, n) in list"
:key="n"
:title="item.title"
class="list-item"
>
{{ item.title }}
</slot-component>
<button #click="add">add</button>
</div>
</div>
Use $attrs — call updated
Vue.component('slot-component', {
created() {
console.log('created', this._uid);
},
updated() {
console.log('updated', this._uid);
},
template: `<div>{{ $attrs.title }}</div>`
})
new Vue({
el: '#app',
data() {
return {
list: []
}
},
methods: {
add() {
this.list.push({ title: 'some' });
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<div id="app">
<div class="list">
<slot-component
v-for="(item, n) in list"
:key="n"
:title="item.title"
class="list-item"
>
</slot-component>
<button #click="add">add</button>
</div>
</div>
Use slot — call updated
Vue.component('slot-component', {
created() {
console.log('created', this._uid);
},
updated() {
console.log('updated', this._uid);
},
template: `<div><slot></slot></div>`
})
new Vue({
el: '#app',
data() {
return {
list: []
}
},
methods: {
add() {
this.list.push({ title: 'some' });
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<div id="app">
<div class="list">
<slot-component
v-for="(item, n) in list"
:key="n"
:title="item.title"
class="list-item"
>
<template #default></template>
</slot-component>
<button #click="add">add</button>
</div>
</div>
The behaviour who seems "weird" is all time because vue binding.
You'r array is update so all property inside is update, someone can have a nice explanation on that because it's too deep.
But the solution is not use a update function on your child (if you don't want update something on every child), but set a watcher on what you want and do something in that case.
Like if you update a title on a child you do that:
watch: {
title(value) {
console.log(value)
}
}
Update:
For the two last example in your update section, like i explain for me it's expected, it's seems weird yes, but it's binding with vue.
About the first, you use a props so you pass a string in your component and nothing else. He have no reason to update.
For the second you do the same thing but with a slot, the only explanation for me it's, when you initialise a slot (even empty) the slot access to the parent data, and because binding is update.
I found this:
https://vuejs.org/guide/components/slots.html#render-scope
Slot content has access to the data scope of the parent component,
because it is defined in the parent.
Be honest it's assumption, if anyone have a other explanation i want to know it !

Vue3 updating data value is updating prop too

Don't know if this is the normal behaviour, I'm kind of new to Vue, but it's driving me nuts. Hope someone here have any clue about what's happpening...
This is my export:
props: [
'asset', //--- asset.price = 50
],
data() {
return {
local_asset: this.asset
}
}
Then, I update the value of a local_asset value with v-model:
<input type="number" v-model="local_asset.price" #change="test" />
And on filling the input with i.e. 100, it results in prop asset being changed too:
methods: {
test() {
console.log(this.local_asset.price) //--- console >> 100
console.log(this.asset.price) //--- console >> 100
}
}
Am I doing it wrong? Sorry if my code is a nonsense. Please help...
You need to copy value , not reference:
Vue.component('Child', {
template: `
<div class="">
<input type="number" v-model="local_asset.price" />
<div>data: {{ local_asset }}</div>
</div>
`,
props: [
'asset',
],
data() {
return {
local_asset: {...this.asset}
}
},
})
new Vue({
el: '#demo',
data() {
return {
asset: {price: 50}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div>prop: {{ asset }}</div>
<Child :asset="asset" />
</div>
If your data in primitive (String, Number, BigInt, Boolean, undefined, and null) you can use
data() {
return {
local_asset: JSON.parse(JSON.stringify(this.asset))
}
}

Vue resets child Component data on props update

I have child component, that has some internal data, that should not be changed from outside. But when I update prop from parent component, this internal data is reset.
Basically in example below, when we change title from outside, value is set back to empty ''. How can I make value persistent with Child component props update?
Child.vue
<template>
<div class="child">
<h2>{{title}}</h2>
<input type="text" :value="value" v-on:change="$emit('change', $event.target.value)">
</div>
</template>
<script>
export default {
props: {
title: {
default: 'Just title'
}
},
data() {
return {
value: ''
}
}
}
</script>
Parent.vue
<template>
<div class="parent">
<Child :title="title" v-on:change="processTitle($event)"></Child>
</div>
</template>
<script>
import Child from './Child';
export default {
data() {
return {
title: 'Title from parent'
}
},
methods: {
processTitle(value) {
this.title = value.reverse();
}
}
}
</script>
You are not setting the value data attribute, :value=value means that "if value changes, the input value should pick up that change". But value doesn't change. Use v-model instead if you want to keep it simple.
Vue.component("Child", {
props: {
title: {
default: 'Just title'
}
},
data() {
return {
value: ''
}
},
template: `
<div class="child">
<h2>{{title}}</h2>
<input type="text" v-model="value" v-on:change="$emit('change', $event.target.value)">
</div>
`
})
new Vue({
el: "#app",
data() {
return {
title: 'Title from parent'
}
},
methods: {
processTitle(value) {
this.title = value.split("").reverse().join("");
}
},
template: `
<div class="parent">
<child :title="title" v-on:change="processTitle($event)"></child>
</div>
`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
EDIT
Also, if you want a continuous effect, don't use #change - use #input instead:
Vue.component("Child", {
props: {
title: {
default: 'Just title'
}
},
data() {
return {
value: ''
}
},
template: `
<div class="child">
<h2>{{title}}</h2>
<input type="text" v-model="value" v-on:input="$emit('change', $event.target.value)">
</div>
`
})
new Vue({
el: "#app",
data() {
return {
title: 'Title from parent'
}
},
methods: {
processTitle(value) {
this.title = value.split("").reverse().join("");
}
},
template: `
<div class="parent">
<child :title="title" v-on:change="processTitle($event)"></child>
</div>
`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

how to enable v-model binding when building a custom components from other custom components

I am able to build a simple textbox component from <input /> and setup v-model binding correctly.
I'm trying to do same with a custom component: vs-input from vuesax.
Following the pattern below does not work as expected:
<template>
<div>
<vs-input type="text" v-model="value" #input="text_changed($event)" />
<!-- <input type="text" :value="value" #input="$emit('input', $event.target.value)" /> -->
</div>
</template>
<script>
export default {
name: 'TestField',
props: {
value: {
type: String,
default: ''
}
},
data() {
return {}
},
methods: {
text_changed(val) {
console.log(val)
// this.$emit('input', val)
}
}
}
</script>
In building custom components from other custom components is there anything particular we should look out for to get v-model binding working properly?
Following code might help you.(Sample code try it in codepen)
updating props inside a child component
//html
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ message }}</p>
<input type="text" :value="test" #change="abc">
{{ test }}
</div>
//VUE CODE
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
},
props:{
test:{
type:String,
default:''
}
},
methods:{
abc:function(event){
//console.log("abc");
console.log(event.target.value);
this.test=event.target.value;
}
}
})
I prefer to interface props with computed:
<template>
<div>
<vs-input type="text" v-model="cValue" />
</div>
</template>
<script>
export default {
name: 'TestField',
props: {
value: {
type: String,
default: ''
}
},
data() {
return {}
},
computed: {
cValue: {
get: function(){
return this.value;
},
set: function(val){
// do w/e
this.$emit('input', val)
}
}
}
}
</script>
Computed Setter

vue.js – get new data information

I'm building a chrome extension using vue.js. In one of my vue components I get tab informations of the current tab and wanna display this information in my template. This is my code:
<template>
<div>
<p>{{ tab.url }}</p>
</div>
</template>
<script>
export default {
data() {
return {
tab: {},
};
},
created: function() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
this.tab = tabs[0];
});
},
};
</script>
The Problem is, that the template gets the data before it's filled through the function. What is the best solution for this problem, when the tab data doesn't change after it is set once.
Do I have to use the watched property, although the data is only changed once?
// EDITED:
I've implemented the solution, but it still doesn't work. Here is my code:
<template>
<div>
<div v-if="tabInfo">
<p>set time limit for:</p>
<p>{{ tabInfo.url }}</p>
</div>
<div v-else> loading... </div>
</div>
</template>
<script>
export default {
data() {
return {
tabInfo: null,
};
},
mounted() {
this.getData();
},
methods: {
getData() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
console.log(tabs[0]);
this.tabInfo = tabs[0];
});
},
},
};
</script>
The console.log statement in my getData function writes the correct object in the console. But the template only shows the else case (loading...).
// EDIT EDIT
Found the error: I used 'this' in the callback function to reference my data but the context of this inside the callback function is an other one.
So the solution is to use
let self = this;
before the callback function and reference the data with
self.tab
You could initialize tab to null (instead of {}) and use v-if="tabs" in your template, similar to this:
// template
<template>
<div v-if="tab">
{{ tab.label }}
<p>{{ tab.body }}</p>
</div>
</template>
// script
data() {
return {
tab: null,
}
}
new Vue({
el: '#app',
data() {
return {
tab: null,
}
},
mounted() {
this.getData();
},
methods: {
getData() {
fetch('https://reqres.in/api/users/2?delay=1')
.then(resp => resp.json())
.then(user => this.tab = user.data)
.catch(err => console.error(err));
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<div v-if="tab">
<img :src="tab.avatar" width="200">
<p>{{tab.first_name}} {{tab.last_name}}</p>
</div>
<div v-else>Loading...</div>
</div>