Synchronize result with value changed in vue.js - javascript

I wrote .vue file like below to change h1#msg after 100ms.
<template>
<div id="main">
<h1 id="msg">{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'Top',
data () {
let a=['TEST']
setTimeout((function(a){a[0]='test'}),100)
return {
msg: a
}
}
}
</script>
<style>
</style>
However I cannot change state by this code. I tried to use Array to pass value by reference.
I don't like to use querySelector(), because it forces me to add attitude in HTML and arguments for methods.

Dont write javascript inside data(), the correct is this code:
<script>
export default {
name: 'top',
data () {
return {
msg: 'test'
}
}
mounted() {
setTimeout(() => this.msg = 'Bu!', 100)
}
}
</script>

Try this code snippets
<template>
<div id="main">
<h1 id="msg">{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'Top',
data () {
return {
msg: 'a'
}
},
created() {
setTimeout(() => this.msg = 'Hello World!', 100)
}
}
</script>

Your data should just declare the variable to whatever you want it to be before the change. Then do the timeout in mounted.

Related

Can I data bind a function in Vue js?

is it possible to data bind a function in Vue?
In the template I have something like: <title> {{nameofFunction()}}</title>
When I run it, it just says native function on the page.
Thanks.
There is also such thing as "computed property" in Vue, designed to do exactly this:
<template>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data:() => ({
message: 'Hello'
}),
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
}
</script>
yes you can. Could you share how are you defining your data options?
Here I have an example that works both in Vue2 and Vue3
<template>
<div id="app">
<h1>{{messageHelloFn()}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
messageHelloFn: (name = 'Lucas') => {
return `Hello ${name}`
}
};
}
};
</script>
Live example: https://codepen.io/LucasFer/pen/abywRMW
a.js
const func = (str) => str
export default fn
<template>
<div id="app">
<div v-for="item in items">
{{ getTime(item) }}
</div>
<div>
{{ fn('a') }}
</div>
<div>
{{ func('b') }}
</div>
</div>
</template>
<script>
import func from './a.js'
export default {
data () {
return {
items: ['123123', '456456'],
fn: (str) => str
}
},
methods: {
getTime (v) {
return v + '123'
}
}
};
</script>

emit value from mounted in child.vue to parent.vue

I'm working with BootstrapVue.
I need to emit a value to my parent.vue - but my code line this.$emit('info', this.hide); doesn't work out.
If I console.log(this.hide) i get my value correct in this case false, otherwise if my if-statement is correct I get it true.
What is the mistake in here?
script of my child.vue:
data(){
return {
hide: true,
}
}
mounted() {
if (statement) {
if(some statement) {
//do something
} else {
this.hide = false;
console.log(this.hide); //HERE I GET CORRECT VALUE
this.$emit('info', this.hide); //THIS DOESNT WORK
}
}
}
How it should work in my parent.vue:
<template>
<div #info="info">
<div> //THIS DIV SHOULD BE SHOWN IF this.hide = false
</div>
<div> //THIS DIV SHOULD BE SHOWN IF this.hide = true
</div>
</div>
</template>
Try something like following snippet :
Vue.component('Child', {
template: `
<div class="">
child
<button #click="changeHide">change hide</button>
</div>
`,
data(){
return {
hide: true,
}
},
methods: {
changeHide() {
this.hide = !this.hide
this.sendInfo()
},
sendInfo() {
this.$emit('info', this.hide);
}
},
mounted() {
//if (statement) {
//if(some statement) {
//do something
//} else {
this.hide = false;
this.sendInfo()
//}
}
})
new Vue({
el: '#demo',
data(){
return {
info: null,
}
},
methods: {
setInfo(val) {
this.info = val
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-if="!info"> //THIS DIV SHOULD BE SHOWN IF this.hide = false
</div>
<div v-if="info"> //THIS DIV SHOULD BE SHOWN IF this.hide = true
</div>
<p>from child info is: {{ info }}</p>
<Child #info="setInfo" />
</div>
Ideally in App.vue (Parent)
you should have something like
<login #info="someHandler"></login>
there is no need to go for a child component if you gonna jus use to manage some logic. It is appropriate only if have some contents in the template.
Also placing emit handler on some div. Thats not how emit works
Below is a simple working example
App.vue (parent)
<template>
<h1>{{ title }}</h1>
<Child #changeTitle="ChangeT($event)" />
</template>
<script>
import Child from "./components/Child"
export default{
name:'App',
components: {
Child,
},
data()
{
return{
title:'Rick Grimes'
}
},
methods:{
ChangeT(title)
{
this.title=title;
},
}
</script>
<style></style>
Child.vue
<template lang="html">
<button type="button" #click='passEvent'> Update me</button>
</template>
<script>
export default {
name:'Child',
methods:{
passEvent()
{
this.$emit('changeTitle','Awesome ')
}
}
}
</script>
<style lang="css" scoped>
</style>

vuejs: v-on does not trigger function

I have an input component that should call a method getUserSearch when the user types, and update the variable v_on_search with the variable v_model_search value.
I am displaying the content with the variables: v_model_search and v_on_search to test, although only the v-model seems to be working.
<template>
<div>
<input type="text" placeholder="search here" v-model="v_model_search" v-on:oninput="getUserSearch()">
<p>{{v_model_search}}</p>
<p>{{v_on_search}}</p>
</div>
</template>
<script>
export default {
name: 'SearchBox',
data () {
return {
v_model_search: '',
v_on_search: ''
}
},
methods: {
getUserSearch ()
{
this.v_on_search = this.v_model_search
}
}
}
</script>
Try
v-on:input="getUserSearch()"
or shorter
#input="getUserSearch()"
Vue recognizes HTML events but they don't have the "on" prefix

how to move items to another component by click - vue.js

I was wondering how can I move my items -> book, from one component to another. I took this books from api and I show them in the list, so I have an ID.
<template>
<v-flex v-for="(book, index) in allBooks">
<div>Title: {{ book.title }}</div>
<i #click="markAsFavorite(book)" :class="{isActive: isMark}" class="fas fa-heart"></i>
</template>
//component books
<script>
name: 'Books',
data () {
return {
allBooks: [],
isMark: false,
favouriteBooks: []
}
},
mounted() {
axios.get("https://www.googleapis.com/books/v1/volumes?q=id:" + this.id)
.then(response => {
console.log(response)
this.allBooks = response.data.items.map(item => ({...item, isMark: false}))
console.log(this.allBooks)
})
.catch(error => {
console.log(error)
})
},
methods: {
markAsFavorite(book) {
this.isMark = !this.isMark
let favouriteAllBooks = this.favouriteBooks.push(book => {
book.id = // i dont know what?
})
},
}
</script>
//component favourite
<template>
<div class=showFavouriteBook>
<p></p>
</div>
</template>
I tried to compare this marked book ID to something, and then this array with marked books show in second template favourite. But I have no idea how to do this. Maybe somebody can prompt me something?
You should use a global eventBus for that. An 'eventBus' is another instance of Vue which is used to pass data via components tied to the main application.
At the root script of your application append the following:
const eventBus = new Vue({
data: function() {
return {
some_var: null,
}
}
});
You can use Vue mixin to have your event bus accessible globally easily:
Vue.mixin({
data: function() {
return {
eventBus: eventBus,
}
}
});
Now when you want to pass data between components you can use the bus:
Component 1
// for the sake of demo I'll use mounted method, which is invoked each time component is mounted
<script>
export default {
mounted: function() {
this.eventBus.some_var = 'it works!'
}
}
</script>
Component 2
<template>
<div>
{{ eventBus.some_var }} <!-- it works -->
</div>
</template>
In addition you can use $emit and $on.
Component 1
// for the sake of demo I'll use mounted method, which is invoked each time component is mounted
<script>
export default {
mounted: function() {
// emit 'emittedVarValue' event with parameter 'it works'
this.eventBus.$emit('emittedVarValue', 'it works!')
}
}
</script>
Component 2
<template>
<div>
{{ some_var }} <!-- "it works" once eventBus receives event "emittedVarValue" -->
</div>
</template>
<script>
export default {
data: function() {
return {
some_var: null
}
},
mounted: function() {
// waiting for "emittedVarValue" event
this.eventBus.$on('emittedVarValue', (data)=>{
this.some_var = data;
})
}
}
</script>
Hope this answer helps you.

Let 2 single file components communicate with each other

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

Categories

Resources