I have a js file that exports a variable and increases it every second
let total = 0
setInterval(function() {
total++
}, 1000)
export { total }
and a Vue component that prints said variable.
<template>
<div id="app">
{{ total }}
</div>
</template>
<script>
import {
total,
} from "./worker";
</script>
how can I make total reactive?
It's not possible with value types because value types are passed by value (value is just copied). What you need is to pass a reference to an object...
counter.js
let counter = {
total: 0
};
setInterval(function() {
counter.total++;
}, 1000);
export default counter;
<template>
<div>
<h1>{{ counter.total }}</h1>
</div>
</template>
<script>
import cnt from "#/counter";
export default {
name: "HelloWorld",
data() {
return {
counter: cnt
};
}
};
</script>
Related
Vue newbie here. I'm trying to pass some props from parent to child, but I get the "variable is assigned a value but never used".
Parent:
<template>
<TextBox :heading="heading1" :body="body1" />
</template>
<script>
import TextBox from "./components/TextBox.vue";
import { ref } from "vue";
export default {
name: "App",
components: {
TextBox,
},
setup() {
const heading1 = ref("Primo titolo");
const body1 = ref("Primo corpo del testo");
},
};
</script>
Child:
<template>
<h1>{{ heading }}</h1>
<p>{{ body }}</p>
</template>
<script>
export default {
name: 'TextBox',
props: {
heading: String,
body: String,
}
}
</script>
What am I missing? Thank you!
If you are using composition API setup function you need to return, or you can use data function from options API :
const { ref } = Vue
const app = Vue.createApp({
setup() {
const heading1 = ref("Primo titolo");
const body1 = ref("Primo corpo del testo");
return { heading1, body1 }
},
})
app.component('TextBox', {
template: `
<h1>{{ heading }}</h1>
<p>{{ body }}</p>
`,
props: {
heading: String,
body: String,
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<text-box :heading="heading1" :body="body1" />
</div>
I'm trying to change a variable that has a data type 'boolean'. When the page is first loaded, the data works well. However, when the page is reloaded, the variable is updated locally in the method, but not in the global data section. Therefore in the console, I keep receiving an error "Uncaught (in promise) TypeError: Cannot read property 'value' of undefined at invokeDirectiveHook"
Is there something I've missed?
<template>
<p>Value: {{ val }}</p>
<button #click="changeMe">Click Me</button>
</template>
<script>
import { ref } from 'vue';
export default {
data() {
return {
val: ref(false);
},
},
methods: {
changeMe() {
this.val = !this.val;
}
}
}
</script>
please don't mix the options API with the composition API
Options API
Vue.createApp({
data() {
return {
val: false
}
},
methods: {
changeMe() {
this.val = !this.val
}
}
}).mount('#demo')
<script src="https://unpkg.com/vue#next"></script>
<div id="demo" class="demo">
<p>Value: {{ val }}</p>
<button #click="changeMe">Click Me</button>
</div>
Composition API
const { createApp, ref } = Vue;
const app = createApp({
setup() {
let val = ref(false)
function changeMe() {
val.value = !val.value
}
return {
val,
changeMe
}
}
});
app.mount("#app");
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<p>Value: {{ val }}</p>
<button #click="changeMe">Click Me</button>
</div>
Compositions API (short)
// Composition API
<template>
<p>Value: {{ val }}</p>
<button #click="changeMe">Click Me</button>
</template>
<script setup>
import { ref } from 'vue'
const val = ref(false)
function changeMe() {
val.value = !val.value
}
</script>
the <script setup> is now included in the 3.2 version
I have a level 2 input field component that i am using. I want to reset on button click from the parent component. I am trying to pass the data to base initial input field and then emitting back to the parent.
My question is that when i try to reset the data on button click the value from the parent component its not working.
Data is not set to null and the values remain as 123.
What wrong I am doing in the following code.
Any help would be appreciated.
Base Input
<template>
<input
v-model="myValue"
type="number"
inputmode="numeric"
#input="$emit( 'input', $event.target.value )"
/>
</template>
<script>
export default {
data () {
return {
myValue: undefined
};
}
}
};
</script>
Level 01
<template>
<div class="c-floating-label">
<input-number #input="passValue" />
</div>
</template>
<script>
import InputNumber from '../../atoms/form-controls/BaseInput';
export default {
components: {
InputNumber
}
methods: {
passValue: function (value) {
this.$emit('input', value);
}
}
};
</script>
Main Component
<div>
<level-01
:required="true"
:v-model="datax.cardNumber"
value="datax.cardNumber"
/>
<button #click="reset">click me</button>
</div>
<script>
data () {
return {
datax: {
cardNumber: undefined
}
};
},
created() {
this.datax.cardNumber = 123;
},
methods: {
reset () {
this.datax.cardNumber = null;
},
</script>
You missed binding on MainComponent
<level-01
:required="true"
:v-model="datax.cardNumber"
:value="datax.cardNumber"
/>
Note :value="datax.cardNumber" is correct
Second, in level-01 you do not bind value prop (not defined at all)
<template>
<div class="c-floating-label">
<input-number #input="passValue" :value="$attrs.value"/>
</div>
</template>
<script>
import InputNumber from '../../atoms/form-controls/BaseInput';
export default {
components: {
InputNumber
},
methods: {
passValue: function (value) {
this.$emit('input', value);
}
}
};
</script>
And finally BaseComponent:
<template>
<input
:value="$attrs.value"
type="number"
inputmode="numeric"
#input="$emit( 'input', $event )"
/>
</template>
<script>
export default {
data () {
return {
// myValue: undefined
};
}
}
};
</script>
How can I let 2 single file components communicate with each other.
For example: I have 2 file components. Content.vue and a Aside.vue
How can i create something like, when I click on a button inside Aside.vue that something will update inside Content.vue
this is how the 2 single file compontents look inside the index.html:
<div class="container articleContainer">
<article-content></article-content>
<article-aside></article-aside>
</div>
Aside.vue:
<template>
<aside>
<span #click="updateCounter">Dit is een aside.</span>
</aside>
</template>
<script>
export default {
data() {
return {
aside: "aside message"
}
}
}
</script>
Content.vue
<template>
<article>
<p>{{ counter }}</p>
<button #click="updateCounter">Update Counter</button>
</article>
</template>
<script>
export default {
data() {
return {
counter: 0
}
}
methods: {
updateCounter: function() {
this.counter = this.counter + 2;
},
}
}
</script>
When I click on the span inside the Aside template how can I use updateCounter to update the counter inside Content.vue.
if your app is not aas big or complex to use vuex , you can set up an EventBus like this:
export const EventBus = new Vue();// in your main.js file
in Aside.vue:
<template>
<aside>
<span #click="updateCounter">Dit is een aside.</span>
</aside>
</template>
<script>
import {EventBus} from './path/to/main.js'
export default {
data() {
return {
aside: "aside message"
}
},
methods:{
updateCounter(){
EventBus.emit('updateCounter');
}
}
}
</script>
in Content.vue
<template>
<article>
<p>{{ counter }}</p>
<button #click="updateCounter">Update Counter</button>
</article>
</template>
<script>
import {EventBus} from './path/to/main.js'
export default {
data() {
return {
counter: 0
}
}
created() {
EventBus.on('updateCounter', () => {
this.counter = this.counter + 2;
});
},
methods: {
updateCounter: function() {
this.counter = this.counter + 2;
},
}
}
</script>
Option 1: Have a value in the App.vue that gets reflected by both the components. (That's the this.$parent.someParentMethod(someValue);-way, which would be mixed with props).
Option 2 (way easier, cleaner and best-practice): vuex
Communication between any components using Event Bus
Event Bus is not limited to a parent-child relation. You can share information between any components.
<script>
export default
name: 'ComponentA',
methods: {
sendGlobalMessage() {
this.$root.$emit('message_from_a', arg1, arg2);
}
}
}
</script>
In the above ComponentA, we are firing an event “message_from_a” and passing arguments. Arguments are optional here. Any other component can listen to this event.
<script>
export default
name: 'ComponentB',
mounted() {
this.$root.$on('message_from_a', (arg1, arg2) => {
console.log('Message received');
});
}
}
</script>
In ComponentB to listen an event, we have to register it first. We can do so by putting an event listener inside mounted() callback. This callback will be triggered when an event is fired from any component.
source
I want to raise a counter in my vue component every time I use the component. The goal should be a name with a suffix of counter i.e. name="tool-2"
Here is my .vue file:
ToolGuiComponent.vue:
<template>
<div>
<label>{{elementName}}</label>
<input type="text" :name="getCount()"></input>
</div>
</template>
<script>
export default {
name: 'tool-gui-component',
props : ['elementName'],
data : function(){
return {
counter : 0
}
},
created : function(){
this.counter++
},
methods : {
getCount : function() {
return "tool-"+this.counter
}
}
}
</script>
<style>
</style>
I tried it with the created hook but it only raises the counter by 1. Using ready did not helped either. Sadly I could not find any API listing of component hooks.
In your case counter is scoped variable and it is created every time you create a component, so you will only increment it once per every instance of your component.
You can create "per module" variable and increment it:
<template>
<div>
<label>{{elementName}}</label>
<input type="text" :name="getCount()"></input>
</div>
</template>
<script>
var counter = 0;
export default {
name: 'tool-gui-component',
props : ['elementName'],
created : function(){
counter++
},
methods : {
getCount : function() {
return "tool-" + counter
}
}
}
</script>
EDIT:
Also in your case, you don't even need getCount function, you can do it as simply as that:
<template>
<div>
<label>{{elementName}}</label>
<input type="text" :name="name"></input>
</div>
</template>
<script>
var counter = 0;
export default {
name: 'tool-gui-component',
props : ['elementName'],
data() {
name: 'tool-' + (counter++)
}
}
</script>
Reason being is that .data() function will be called every time the new instance of the component is created, so it is exactly what you need.