Vue async component callback - javascript

<template>
<div>
<AsyncComponent1></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2></AsyncComponent2>
</div>
</template>
<script>
export default {
name: "My Component"
components: {
AsyncComponent1: () => import("./AsyncComponent1"),
AsyncComponent2: () => import("./AsyncComponent2")
}
};
</script>
I'm loading two components asynchronously within a component but I need one of the components to render after the other. I wonder if thats possible?

Add a v-if to a ref in the other component.
<template>
<div>
<AsyncComponent1 ref="c1"></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2 v-if="$refs.c1"></AsyncComponent2>
</div>
</template>

You could have the first component emit an event, that is listened to by the parent and used to toggle the second component
<template>
<div>
<AsyncComponent1 v-on:loaded="componentLoaded"></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2 v-if="hasComponent"></AsyncComponent2>
</div>
</template>
<script>
export default {
name: "My Component",
components: {
AsyncComponent1: () => import("./AsyncComponent1"),
AsyncComponent2: () => import("./AsyncComponent2")
},
data: {
hasComponent: false
},
methods: {
componentLoaded() {
this.hasComponent = true;
}
}
};
</script>
And then in AsyncComponent1.vue:
...
mounted() {
this.$emit("loaded");
}
...

Related

How to hide content when clicked checkbox from different components in vuejs?

//inputtwo.vue
<template>
<div><input type="checkbox" v-model="checked" />one</div>
</template>
<script>
export default {
name: "inputtwo",
components: {},
data() {
return {};
},
};
</script>
//maincontent.vue
<template>
<div>
<div class="container" id="app-container" v-if="!checked">
<p>Text is visible</p>
</div>
<common />
</div>
</template>
<script>
export default {
name: "maincontent",
components: {},
data() {
return {
checked: false,
};
},
methods: {
hidecont() {
this.checked = !this.checked;
},
},
};
</script>
//inputone.vue
<template>
<div><input type="checkbox" v-model="checked" />one</div>
</template>
<script>
export default {
name: "inputone",
components: {},
data() {
return {};
},
};
</script>
How to hide content of checkbox from different components in Vuejs
I have three components called inputone(contains checkbox with v-model),inputtwo (contains checkbox with v-model),maincontent.(having some content and logic), So when user click on checkboxes from either one checckbox(one,two). i schould hide the content.
Codesanfdbox link https://codesandbox.io/s/crimson-fog-wx9uo?file=/src/components/maincontent/maincontent.vue
reference code:- https://codepen.io/dhanunjayt/pen/mdBeVMK
You are actually not syncing the data between components. The main content checked never changes. You have to communicate data between parent and child components or this won't work. And try using reusable components like instead of creating inputone and inputtwo for same checkbox create a generic checkbox component and pass props to it. It is a good practice and keeps the codebase more manageable in the longer run.
App.vue
<template>
<div id="app">
<maincontent :showContent="showContent" />
<inputcheckbox text="one" v-model="checkedOne" />
<inputcheckbox text="two" v-model="checkedTwo" />
</div>
</template>
<script>
import maincontent from "./components/maincontent/maincontent.vue";
import inputcheckbox from "./components/a/inputcheckbox.vue";
export default {
name: "App",
components: {
maincontent,
inputcheckbox,
},
computed: {
showContent() {
return !(this.checkedOne || this.checkedTwo);
},
},
data() {
return {
checkedOne: false,
checkedTwo: false,
};
},
};
</script>
checkbox component:
<template>
<div>
<input
type="checkbox"
:checked="value"
#change="$emit('input', $event.target.checked)"
/>
{{ text }}
</div>
</template>
<script>
export default {
name: "inputcheckbox",
props: ["value", "text"],
};
</script>
Content:
<template>
<div class="container" id="app-container" v-if="showContent">
<p>Text is visible</p>
</div>
</template>
<script>
export default {
name: "maincontent",
props: ["showContent"]
}
</script>
https://codesandbox.io/embed/confident-buck-kith5?fontsize=14&hidenavigation=1&theme=dark
Hope this helps and you can learn about passing data between parent and child components in Vue documentation: https://v2.vuejs.org/v2/guide/components.html
Consider using Vuex to store and maintain the state of the checkbox. If you're not familiar with Vuex, it's a reactive datastore. The information in the datastore is accessible across your entire application.

How to store a value from another component's data?

I have two components, is there a way to store value from another component's data?
Here is Create.vue
<template>
<div id="main">
<Editor />
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
}
</script>
And here is the _Create_Editor.vue.
<template>
//sample input for demonstration purposes
<input type="text" class="form-control" v-model="text"/>
</template>
The code above returns an error:
Property or method "text" is not defined on the instance but referenced during render
I want everytime I type the data: text from Create.vue has the value of it.
How can I possibly make this? Please help.
You can do this by using $emit.
Create.vue
<template>
<div id="main">
<Editor
#edit={onChangeText}
/>
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
methods: {
onChangeText: function (value) {
this.text = value
}
}
}
</script>
_Create_Editor.vue
<template>
//sample input for demonstration purposes
<input
type="text"
class="form-control"
#change="onChange"
/>
</template>
<script>
export default {
methods: {
onChange: function (event) {
this.$emit('edit', event.target.value)
}
}
}
</script>

How to test if a component emits an event in Vue?

I have two components. Child component emits an 'input' event when it's value changed and parent component takes this value with v-model. I'm testing ChildComponent. I need to write a test with Vue-test-utils to verify it works.
ParentComponent.vue:
<template>
<div>
<child-component v-model="search"></child-component>
<other-component></other-component>
...
</div>
</template>
ChildComponent.vue:
<template>
<input :value="value" #change="notifyChange($event.target.value)"></input>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
#Component
export default class ChildComponent extends Vue {
#Prop({ default: '' }) readonly value!: string
notifyChange(value: string) {
this.$emit('input', value)
}
}
</script>
child-component.spec.ts:
describe('ChildComponent', () => {
let wrapper: any
before(() => {
wrapper = VueTestUtils.shallowMount(ChildComponent, {})
})
it(`Should emit 'input' event when value change`, () => {
const rootWrapper = VueTestUtils.shallowMount(ParentComponent)
wrapper.vm.value = 'Value'
wrapper.findAll('input').at(0).trigger('change')
assert.isTrue(!!rootWrapper.vm.search)
})
})
I didn't write the exact same code but the logic is like this.
My components work properly. 'child-component.spec.ts' doesn't work. I need to write a test for it.
TESTED.
This is a simple way of testing an emit, if someone is looking for this.
in your test describe write this.
describe('Close Button method', () => {
it('emits return false if button is clicked', (done) => {
wrapper.find('button').trigger('click')
wrapper.vm.$nextTick(() => {
wrapper.vm.closeModal() //closeModal is my method
expect(wrapper.emitted().input[0]).toEqual([false]) //test if it changes
done()
})
})
})
my vue comp
<div v-if="closeButton == true">
<button
#click="closeModal()"
>
...
</button>
</div>
my props in vue comp
props: {
value: {
type: Boolean,
default: false
},
my methods in vue comp
methods: {
closeModal() {
this.$emit('input', !this.value)
}
}
Here's an example that will help you:
Child Component.vue
<template>
<div>
<h2>{{ numbers }}</h2>
<input v-model="number" type="number" />
<button #click="$emit('number-added', Number(number))">
Add new number
</button>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: {
numbers: Array
},
data() {
return {
number: 0
};
}
};
</script>
Parent Component.vue
<template>
<div>
<ChildComponent
:numbers="numbers"
#number-added="numbers.push($event)"
/>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
data() {
return {
numbers: [1, 2, 3]
};
},
components: {
ChildComponent
}
};
</script>
Follow this article: https://medium.com/fullstackio/managing-state-in-vue-js-23a0352b1c87
I hope this will help you.
in your parent component listen to the emitted event "input"
<template>
<div>
<child-component #input="get_input_value" v-model="search"></child-component>
<other-component></other-component>
...
</div>
</template>
and in your script add method get_input_value()
<script>
...
methods:
get_input_value(value){
console.log(value)
}
</script>

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

Vue.js - Using parent data in component

How I can get access to parent's data variable (limitByNumber) in my child component Post?
I tried to use prop but it doesn't work.
Parent:
import Post from './components/Post.vue';
new Vue ({
el: 'body',
components: { Post },
data: {
limitByNumber: 4
}
});
Component Post:
<template>
<div class="Post" v-for="post in list | limitBy limitByNumber">
<!-- Blog Post -->
....
</div>
</template>
<!-- script -->
<script>
export default {
props: ['list', 'limitByNumber'],
created() {
this.list = JSON.parse(this.list);
}
}
</script>
Option 1
Use this.$parent.limitByNumber from child component. So your Component template would be like this
<template>
<div class="Post" v-for="post in list | limitBy this.$parent.limitByNumber" />
</template>
Option 2
If you want to use props, you can also achieve what you want. Like this.
Parent
<template>
<post :limit="limitByNumber" />
</template>
<script>
export default {
data () {
return {
limitByNumber: 4
}
}
}
</script>
Child Pots
<template>
<div class="Post" v-for="post in list | limitBy limit">
<!-- Blog Post -->
....
</div>
</template>
<script>
export default {
props: ['list', 'limit'],
created() {
this.list = JSON.parse(this.list);
}
}
</script>
If you want to access some specific parent, you can name all components like this:
export default {
name: 'LayoutDefault'
And then add some function (maybe like vue.prototype or Mixin if you need it in all your components). Something like this should do it:
getParent(name) {
let p = this.$parent;
while(typeof p !== 'undefined') {
if (p.$options.name == name) {
return p;
} else {
p = p.$parent;
}
}
return false;
}
and usage could be like this:
this.getParent('LayoutDefault').myVariableOrMethod

Categories

Resources