I am trying to do modals in VueJS 2.0.
My goal is to call it from wherever in DOM is it possible and render component as child of body but communicate with component where it was initialized.
What I have tried is:
...
mounted () {
document.getElementsByTagName('div')[0].appendChild(this.$el);
}
...
Which of course renders element where I want it to be rendered and also communicate with component where it was initialized. But when I try to remove it... I get:
DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
The way I show / hide model in component where modal is initialized including parameter visible: true / false and then:
<modal v-if="visible"></modal>
Any ideas?
Related
I'm trying to write a unit test for a VueJS 2 component that has a dynamic component that changes as the state changes.
<template>
<div>
<component ref="dynamicComponent" id="dynamicComponent" :is="someDynamicType" #custom-event="handleCustomEvent">
</component>
</div>
</template>
What i'm trying to test is that the parent component is handling the custom-event from the child dynamic component correctly. However, the problem I'm running into is that I cannot seem to get a reference to the child dynamic component.
I've tried
await wrapper.findComponent('#dynamicComponent').vm.$emit("custom-event", {});
and
await wrapper.find({ref: 'dynamicComponent'}).vm.$emit("custom-event", {});
and I also tried using the known type of the dynamic component
await wrapper.findComponent(KnownSubType).vm.$emit("custom-event", {});
but in each case, I get the following error
TypeError: Cannot read properties of undefined (reading '$emit')
Is there another way to obtain the component so that I can emit the custom event or is there another way to trigger the event to test my parent component?
I ran into a similar problem writing tests using dynamic components. To ensure that the child component was loaded before manipulating it in my tests I had to flush promises. This can be either written manually like in this answer: https://stackoverflow.com/a/65665052/11015616
or
the flush-promises npm library can be used.
const wrapper = mount(SomeComponent, {options});
await flushPromises();
// manipulate child component
i have three vue.js file. where the parent file (parent.vue) contains data of profile:[]
the data of profile is send to child file (child.vue) using props methods.
the child.vue also has it's own child file (grandchild.vue) that has been pass with the profile data by using props.
grandchildren will send a put request to API to change some data in profile.
my question is. how can i make sure the props will update on every change made in the profile data.
information : (parent.vue = main file, child.vue = drawer(from ant design), grandchild = popover)
i need the child.vue to update the profile data after the grandchild succeed send a put request to the API.
is there any way or reference link so i could make the props update after a put request from grandchild.vue i have tried watch method but the problem is the user need to close the drawer (child.vue) first and re open the drawer to update the props. is there any way the props update without closing the drawer?
example of code :
parent.vue :
// structure
<child.vue
:profile="profile"
/>
child.vue & grandchild.vue :
//script
props : [profile],
profile can be used as {{profile.subsdata}} in html or this.profile.subsdata javascript
Use an emit. Tell the parent component to update via another GET request or just pass the data back directly.
Child Method:
notifyParent () {
this.$emit('updateProfile')
}
Parent Template:
<ChildComponent v-on:updateProfile="someMethod"/>
Parent Method:
someMethod () {
//GET request or whatever
}
More details here: https://v2.vuejs.org/v2/guide/components-custom-events.html
The keyword here is eventBus, you need an eventBus to $emit an event changing the data in the parent component from the grandchild component. If you only need to change up the data 1 layer instead of 2 in this case, you only need custom event + $emit, without the eventBus. But as it's greater than 2 layers, you need eventBus, or even more relegent ways to do state management.
I am working on a chat tool using vue single file components.I am facing a problem,root .vue has child .vue and grandchild .vue, I want to observer children's rendering,to get the root div's height,to change scrollbar position,
i used the $nextTick() http://rc.vuejs.org/api/#vm-nextTick,but it cant observer children's render,so ,is there any way can I try? thanks a lot.
You can use parent child communication of vue to get to know when you child has rendered. Vue provided following event interface:
Listen to an event using $on(eventName)
Trigger an event using
$emit(eventName)
A parent component can listen to the events emitted from a child component using v-on directly in the template where the child component is used.
So you can emit a event in your child component's lifecycle hook like following:
mounted () {
this.$emit('childRendered')
}
In parent component, you can listen to this event or create a method, like following:
this.$on('childRendered', function () {
// change scrollbar position
})
An example of parent child communication: fiddle
This is just for everyone to easily see the workaround that was mentioned by Saurabh in his comment to his answer. I also used the updated lifecycle to wait for the DOM to finish rendering and patching before manipulating it again.
Since updated does not guarantee that all child components have also been re-rendered, use vm.$nextTick inside of updated.
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
Pretty new to vue js here,
Just want to know if is it possible to emit a custom event from the main vue instance (parent) and the components could listen to that custom event and act accordingly when that event is triggered?
I want to trigger a custom event on vue instance mounted lifecycle function then all components can initialize themselves.
ex.
Main vue instance
new Vue( {
el : '#main-app',
mounted : function() {
this.$emit( 'init-app' );
}
} );
Then on the various components, it can listen for the 'init-app' custom event then act accordingly when it is triggered or emitted.
Not sure how to do this coz in vue js event listeners are attached to the html tags? can an event listener or a function in a component be triggered by just the emitting of the event from the parent alone?
Note: I'm using vue js 2.0.3
and my components are global, they are not inline
ex.
Vue.component('my-component', {
template: '#component-template'
});
I could add more components later on.
Thanks in advance.
The correct way to initialize your child components is to use created: life-cycle hook for each of your child components.
Reason: It is quite possible that your child component may not be instantiated when you send your init-app event from the parent component. So, it will never get initialized.
Additional note on events: If you are sending an event from child component to parent component, you should use this.$parent.$emit("my-event-code") and receive it on the parent side as this.$on("my-event-code"). I figured it out recently after hours of trying various methods.
So, if you are trying to send an init-app event from parent to child, you might have to listen on child component as this.$parent.$on("init-app", ...) - I haven't verified this yet, this is my current understanding.
I'm trying to set the instance variable of a child component from it's parent component inside a callback. Using the debugger I can see that the instance variable is set correctly in the callback, but on rendering the child component, the child component does not reflect the changes made.
So, is it illegal to modify a component's state from another component in seaside or am I doing something else wrong?
Example code:
MyParentComponent>> initialize
super initialize.
child := MyChildComponent new.
MyParentComponent>> renderContentOn: html
html render: child.
html anchor
callback: [
child property: 'Something'.
] ; with 'Navigate'.
MyParentComponent>> children
^ Array with: child
You miss some super initialize in the parent component I guess.
I also suggest you don't work this way.
Do a MyParentComponent>>child with
^ child ifNil: [ child := MyChildComponent new ]
Also, don't do a html render: child but html render: self child.
That way you'll be able to swap components easily.
That way you are sure that child has been properly initialized.
After a little experimenting, I found the problem. In one of the rendering methods, I was creating a new component each time the page was rendered instead of reusing the one created in the initialize method.
That other component was used for navigation, where I set which main component was to be displayed based on the menu chosen.
So apparently, modifying state is not illegal in Seaside.